From ae86fca905bce56c21f17c845c2b8c608ca6f209 Mon Sep 17 00:00:00 2001 From: dv Date: Mon, 8 Apr 2024 10:01:40 +0700 Subject: [PATCH] deploy on polygon --- deployments/matic/BorrowLib.json | 44 +- .../matic/ConverterStrategyBaseLib.json | 44 +- deployments/matic/PairBasedStrategyLib.json | 44 +- .../matic/PairBasedStrategyLogicLib.json | 48 +- .../matic/PairBasedStrategyReader.json | 42 +- .../matic/UniswapV3ConverterStrategy.json | 124 +- .../UniswapV3ConverterStrategyLogicLib.json | 48 +- deployments/matic/UniswapV3DebtLib.json | 48 +- package-lock.json | 3597 +++++++++-------- package.json | 2 +- scripts/utils/tx-params.ts | 12 +- 11 files changed, 2240 insertions(+), 1813 deletions(-) diff --git a/deployments/matic/BorrowLib.json b/deployments/matic/BorrowLib.json index 116df101..c787df28 100644 --- a/deployments/matic/BorrowLib.json +++ b/deployments/matic/BorrowLib.json @@ -1,5 +1,5 @@ { - "address": "0xd84c6293b2E190DDd7Ea7F6E00396A840294BDcE", + "address": "0x46aa135654F8A46cDF029059c531EfBd27368220", "abi": [ { "inputs": [], @@ -28,46 +28,46 @@ "type": "function" } ], - "transactionHash": "0x365e32f7eaf2459f49a5c23d1cecb7b3516ea97cce4f1a117ee852aa841a8503", + "transactionHash": "0x1346085023b99c4368363ceaf69ede352f26b215727af84e8adf238fe1d597d3", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0xd84c6293b2E190DDd7Ea7F6E00396A840294BDcE", - "transactionIndex": 94, + "contractAddress": "0x46aa135654F8A46cDF029059c531EfBd27368220", + "transactionIndex": 19, "gasUsed": "2334839", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0xbd0c7e1a1c9294b2fa7010ffe2708f7dd91295386f49ceea71deca7df6f8ffb2", - "transactionHash": "0x365e32f7eaf2459f49a5c23d1cecb7b3516ea97cce4f1a117ee852aa841a8503", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000800000000000000000000000000000800000000000000000000100000000000100000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000040001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0x685d19aaf73a1b1878102a2cb79d014e93836630c34c522ff9845f83d1eeb5e5", + "transactionHash": "0x1346085023b99c4368363ceaf69ede352f26b215727af84e8adf238fe1d597d3", "logs": [ { - "transactionIndex": 94, - "blockNumber": 54802956, - "transactionHash": "0x365e32f7eaf2459f49a5c23d1cecb7b3516ea97cce4f1a117ee852aa841a8503", + "transactionIndex": 19, + "blockNumber": 55572312, + "transactionHash": "0x1346085023b99c4368363ceaf69ede352f26b215727af84e8adf238fe1d597d3", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x000000000000000000000000b95d435df3f8b2a8d8b9c2b7c8766c9ae6ed8cc9" ], - "data": "0x000000000000000000000000000000000000000000000000000c714919cdd9000000000000000000000000000000000000000000000000026d9932e9458a46590000000000000000000000000000000000000000000024355c8e553c6743cdd20000000000000000000000000000000000000000000000026d8cc1a02bbc6d590000000000000000000000000000000000000000000024355c9ac6858111a6d2", - "logIndex": 1492, - "blockHash": "0xbd0c7e1a1c9294b2fa7010ffe2708f7dd91295386f49ceea71deca7df6f8ffb2" + "data": "0x000000000000000000000000000000000000000000000000017568405f1337c6000000000000000000000000000000000000000000000001e4141b05a804944000000000000000000000000000000000000000000000001421524307217f2674000000000000000000000000000000000000000000000001e29eb2c548f15c7a00000000000000000000000000000000000000000000001422c7ab4780925e3a", + "logIndex": 83, + "blockHash": "0x685d19aaf73a1b1878102a2cb79d014e93836630c34c522ff9845f83d1eeb5e5" } ], - "blockNumber": 54802956, - "cumulativeGasUsed": "16483546", + "blockNumber": 55572312, + "cumulativeGasUsed": "4955966", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 15, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MAX_DEEP_RECURSION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SUM_PROPORTIONS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\",\"kind\":\"dev\",\"methods\":{\"prepareToDeposit(ITetuConverter,uint256,address[2],uint256[2],uint256)\":{\"params\":{\"amount_\":\"Amount of underlying that is going to be deposited We assume here, that current balance >= the {amount_}\",\"prop0\":\"Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\",\"thresholds_\":\"Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\",\"tokens_\":\"[Underlying, not underlying]\"},\"returns\":{\"tokenAmounts\":\"Result amounts [A0 (underlying), A1 (not-underlying)]\"}},\"rebalanceAssets(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"addition0\":\"Additional amount A0 of {asset0}. Balance0 = A0 + B0 We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\",\"prop0\":\"Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\",\"threshold0\":\"Min allowed amount of {asset0}-collateral, 0 - use default min value\",\"threshold1\":\"Min allowed amount of {asset1}-collateral, 0 - use default min value\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MAX_DEEP_RECURSION()\":{\"notice\":\"Function {_rebalanceAssets} cannot be called recursively more than twice. Normally one call is enough. Firstly repay(requiredAmount0) is called below. There are two possible results: 1) requiredCost0 <= cost0 2) v.directDebt == 0 There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected because of debt gap. So, we need second cycle.\"},\"SUM_PROPORTIONS()\":{\"notice\":\"prop0 + prop1\"},\"prepareToDeposit(ITetuConverter,uint256,address[2],uint256[2],uint256)\":{\"notice\":\"Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying) Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0} The function is able to make new borrowing and/or close exist debts.\"},\"rebalanceAssets(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\"}},\"notice\":\"Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libs/BorrowLib.sol\":\"BorrowLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x61294361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806324a6c3201461005b57806343f8b62c146100765780634b4bd6f714610098578063d0c9e363146100c5575b600080fd5b610063600281565b6040519081526020015b60405180910390f35b81801561008257600080fd5b506100966100913660046123ca565b6100d4565b005b8180156100a457600080fd5b506100b86100b33660046124e7565b6102ac565b60405161006d9190612585565b610063670de0b6b3a764000081565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152846101225760405162461bcd60e51b81526004016101199190612619565b60405180910390fd5b5060408051808201909152601481527354532d333220746f6f20686967682076616c756560601b6020820152670de0b6b3a764000085106101765760405162461bcd60e51b81526004016101199190612619565b5061017f61230d565b6001600160a01b03808816825286166020820152604081018590526060810184905260808101839052610140810182905260006101bb8a610542565b604080516002808252606082018352929350600092909160208301908036833701905050905088816000815181106101f5576101f561262c565b60200260200101906001600160a01b031690816001600160a01b03168152505087816001815181106102295761022961262c565b60200260200101906001600160a01b031690816001600160a01b0316815250506102558282600261060d565b8460a001516000018560a00151602001829052829052505061029f8360405180604001604052808e6001600160a01b031681526020018d6001600160a01b0316815250600261080c565b5050505050505050505050565b60606102b6612394565b600060405180604001604052806102ec6102e6896000600281106102dc576102dc61262c565b6020020151610a03565b8a610a6e565b81526020016102fc8860016102dc565b90526020870151875160405163dd27ede760e01b81529293506000926001600160a01b038c169263dd27ede79261033c9230929190600190600401612642565b60408051808303816000875af115801561035a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e919061266c565b50865190915081111561048757600081891161039a578861039c565b815b6020890151895160405163954d7e7360e01b81526001600160a01b03808f16600483015292831660248201529116604482015260648101829052909150730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab19063954d7e73906084016040805180830381865af4158015610414573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610438919061266c565b505060408051808201909152806104616104538b60006102dc565b8660005b6020020151610a6e565b815260200161047c6104748b60016102dc565b866001610457565b8152509350506104a0565b6040518060400160405280898152602001600081525092505b6104ad8984898989610a8f565b60408051600280825260608201835290916020830190803683370190505093506104e36104db8860006102dc565b836000610457565b846000815181106104f6576104f661262c565b602090810291909101015261051761050f8860016102dc565b836001610457565b8460018151811061052a5761052a61262c565b60200260200101818152505050505095945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a69190612690565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190612690565b92915050565b6060808267ffffffffffffffff8111156106295761062961244a565b604051908082528060200260200182016040528015610652578160200160208202803683370190505b5091508267ffffffffffffffff81111561066e5761066e61244a565b604051908082528060200260200182016040528015610697578160200160208202803683370190505b50905060005b83811015610803578481815181106106b7576106b761262c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072091906126ad565b61072b90600a6127ca565b82828151811061073d5761073d61262c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061076a5761076a61262c565b60200260200101516040518263ffffffff1660e01b815260040161079d91906001600160a01b0391909116815260200190565b602060405180830381865afa1580156107ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107de91906127d9565b8382815181106107f0576107f061262c565b602090810291909101015260010161069d565b50935093915050565b82516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087791906127d9565b60c084015260208301516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906127d9565b60e084015281518351602085015160405163dd27ede760e01b81526001600160a01b039093169263dd27ede792610928923092600190600401612642565b60408051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a919061266c565b5061010084015281516020840151845160405163dd27ede760e01b81526001600160a01b039093169263dd27ede7926109aa923092600190600401612642565b60408051808303816000875af11580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ec919061266c565b506101208401526109fe838383610f7f565b505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060791906127d9565b6000818311610a7e576000610a88565b610a8882846127f2565b9392505050565b610ac86040518060c001604052806060815260200160608152602001600081526020016000815260200160008152602001606081525090565b6000610ad387610542565b604080516002808252606082018352929350600092909160208301908036833750508751825192935091839150600090610b0f57610b0f61262c565b6001600160a01b0392909216602092830291909101820152860151815182906001908110610b3f57610b3f61262c565b60200260200101906001600160a01b031690816001600160a01b031681525050610b6b8282600261060d565b60208501819052908452805190925060009150610b8a57610b8a61262c565b60200260200101518160000151600081518110610ba957610ba961262c565b602002602001015186600060028110610bc457610bc461262c565b6020020151610bd39190612805565b610bdd919061281c565b6040820152602081015180516001908110610bfa57610bfa61262c565b60200260200101518160000151600181518110610c1957610c1961262c565b602002602001015186600160028110610c3457610c3461262c565b6020020151610c439190612805565b610c4d919061281c565b6060820152610c6482670de0b6b3a76400006127f2565b60808201526060810151610c79908390612805565b81608001518260400151610c8d9190612805565b1115610df55760008160800151838360600151610caa9190612805565b610cb4919061281c565b905060008260000151600081518110610ccf57610ccf61262c565b60200260200101518360200151600081518110610cee57610cee61262c565b6020026020010151838560400151610d0691906127f2565b610d109190612805565b610d1a919061281c565b9050610d2f8660005b6020020151828a6115e7565b608080840151604080516001602082015290810187905260608101919091520160408051808303601f1901815291815260a08501829052875160208901518851925163ca27d10d60e01b8152730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab19463ca27d10d94610dac948f949293909291899160040161283e565b6040805180830381865af4158015610dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dec919061266c565b50505050610f77565b818160600151610e059190612805565b81608001518260400151610e199190612805565b1015610f775760008282608001518360400151610e369190612805565b610e40919061281c565b905060008260000151600181518110610e5b57610e5b61262c565b60200260200101518360200151600181518110610e7a57610e7a61262c565b6020026020010151838560600151610e9291906127f2565b610e9c9190612805565b610ea6919061281c565b9050610eb3866001610d23565b608083810151604080516001602082015290810191909152606081018690520160408051808303601f1901815291815260a08501829052602080890151895191890151925163ca27d10d60e01b8152730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab19463ca27d10d94610f32948f9492939091899160040161283e565b6040805180830381865af4158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f72919061266c565b505050505b505050505050565b60008360a0015160200151600081518110610f9c57610f9c61262c565b60200260200101518460a0015160000151600081518110610fbf57610fbf61262c565b60200260200101518560c00151610fd69190612805565b610fe0919061281c565b905060008460a0015160200151600181518110610fff57610fff61262c565b60200260200101518560a00151600001516001815181106110225761102261262c565b60200260200101518660e001516110399190612805565b611043919061281c565b905060008560a00151602001516000815181106110625761106261262c565b60200260200101518660a00151600001516000815181106110855761108561262c565b602002602001015187610140015161109d9190612805565b6110a7919061281c565b9050806110b48385612886565b1115610f77576000816110c78486612886565b6110d191906127f2565b9050600082670de0b6b3a76400008960400151846110ef9190612805565b6110f9919061281c565b6111039190612886565b90506000670de0b6b3a76400008960400151670de0b6b3a764000061112891906127f2565b6111329085612805565b61113c919061281c565b9050858211156113915760006040518061016001604052808a81526020018b602001516001600160a01b031681526020018b600001516001600160a01b031681526020018b60400151670de0b6b3a764000061119891906127f2565b81526020018b6040015181526020018b60a00151602001516000815181106111c2576111c261262c565b60200260200101518c60a00151600001516001815181106111e5576111e561262c565b60200260200101518d60a00151602001516001815181106112085761120861262c565b60200260200101518e60a001516000015160008151811061122b5761122b61262c565b6020026020010151670de0b6b3a76400006112469190612805565b6112509190612805565b61125a919061281c565b611264919061281c565b81526020018b608001518152602001600081526020018b61014001518152602001600181526020016000815250905060648a610100015110611370576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886112ed5760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160008151811061130b5761130b61262c565b60200260200101518b60a001516020015160008151811061132e5761132e61262c565b6020026020010151898661134291906127f2565b61134c9190612805565b611356919061281c565b905061136a8b83838e61010001518d6116dc565b5061138b565b611388818b60a001518c60e001518d60c001516117a4565b50505b506115df565b858210156115df5760006040518061016001604052808a81526020018b600001516001600160a01b031681526020018b602001516001600160a01b031681526020018b6040015181526020018b60400151670de0b6b3a76400006113f591906127f2565b81526020018b60a00151602001516001815181106114155761141561262c565b60200260200101518c60a00151600001516000815181106114385761143861262c565b60200260200101518d60a001516020015160008151811061145b5761145b61262c565b60200260200101518e60a001516000015160018151811061147e5761147e61262c565b6020026020010151670de0b6b3a76400006114999190612805565b6114a39190612805565b6114ad919061281c565b6114b7919061281c565b81526020018b6060015181526020018b6101400151815260200160008152602001600081526020016001815250905060648a6101200151106115c3576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886115405760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160018151811061155e5761155e61262c565b60200260200101518b60a00151602001516001815181106115815761158161262c565b6020026020010151888561159591906127f2565b61159f9190612805565b6115a9919061281c565b90506115bd8b83838e61012001518d6116dc565b50610dec565b6115db818b60a001518c60c001518d60e001516117a4565b5050505b505050610f77565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015611636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165a91906127d9565b10156109fe5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156116b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d69190612899565b50505050565b6040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152816117295760405162461bcd60e51b81526004016101199190612619565b506000670de0b6b3a76400008560a00151856117459190612805565b61174f919061281c565b9050600061175d8285611911565b90506064811061179b578551516040870151602088015161178092919084611927565b5050865161179b915088906117966001876127f2565b61080c565b50505050505050565b6000808560e00151600014806117bd5750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118075760405162461bcd60e51b81526004016101199190612619565b50610100860151156118825785610100015183106118435761183a86858861010001518661183591906127f2565b611ae9565b91509150611908565b6000611861878787878b610100015161185c91906127f2565b611c82565b5090506118788761187283886127f2565b86611ae9565b9250925050611908565b60e0860151156118fd578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906118e25760405162461bcd60e51b81526004016101199190612619565b5061183a868760e00151866118f791906127f2565b85611ae9565b61183a868585611ae9565b94509492505050565b60008183106119205781610a88565b5090919050565b6040516370a0823160e01b81523060048201526000908190819081906001600160a01b038716906370a0823190602401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199891906127d9565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b81526004016119cf9493929190612642565b60408051808303816000875af11580156119ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a11919061266c565b509050611a2c818710611a245781611a26565b865b83611911565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab2919061266c565b909650905080861115611acc57611ac981876127f2565b95505b611ad98a8a8a8787611e8b565b9550505050509450945094915050565b606083810151608080860151604080516001602082015280820194909452838501919091528051808403909401845291019052600090819081908415611bb957670de0b6b3a7640000876080015188606001518960a0015188611b4c9190612805565b611b569190612805565b611b60919061281c565b611b6a919061281c565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b81525090611bb75760405162461bcd60e51b81526004016101199190612619565b505b6020870151611bd490611bcc84896127f2565b8951516115e7565b730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab163ca27d10d886000015160000151838a602001518b60400151878c611c0e91906127f2565b8d60c001516040518763ffffffff1660e01b8152600401611c349695949392919061283e565b6040805180830381865af4158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061266c565b935093505050935093915050565b6000806000856020015187610140015181518110611ca257611ca261262c565b6020026020010151866000015188610120015181518110611cc557611cc561262c565b6020026020010151876020015189610120015181518110611ce857611ce861262c565b602002602001015188600001518a610140015181518110611d0b57611d0b61262c565b602002602001015187611d1e9190612805565b611d289190612805565b611d32919061281c565b611d3c919061281c565b9050620186a0611d4e61012c82612886565b611d589083612805565b611d62919061281c565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b81525090611db55760405162461bcd60e51b81526004016101199190612619565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e4820152730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab190637de8f56990610104016040805180830381865af4158015611e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7d919061266c565b909890975095505050505050565b6000806064841061206657611eaa6001600160a01b0386168886612070565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015611f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2f91906128bb565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906127d9565b905080851161201057600061201a565b61201a81866127f2565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156120625760405162461bcd60e51b81526004016101199190612619565b5050505b9550959350505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908401526109fe9286929160009161210091851690849061217d565b8051909150156109fe578080602001905181019061211e9190612899565b6109fe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610119565b606061218c8484600085612194565b949350505050565b6060824710156121f55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610119565b600080866001600160a01b0316858760405161221191906128f1565b60006040518083038185875af1925050503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b50915091506122648783838761226f565b979650505050505050565b606083156122de5782516000036122d7576001600160a01b0385163b6122d75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610119565b508161218c565b61218c83838151156122f35781518083602001fd5b8060405162461bcd60e51b81526004016101199190612619565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161236b604051806040016040528060608152602001606081525090565b815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146123c757600080fd5b50565b600080600080600080600080610100898b0312156123e757600080fd5b88356123f2816123b2565b97506020890135612402816123b2565b96506040890135612412816123b2565b95506060890135612422816123b2565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561249157634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f8301126124a857600080fd5b6124b0612460565b8060408401858111156124c257600080fd5b845b818110156124dc5780358452602093840193016124c4565b509095945050505050565b600080600080600060e086880312156124ff57600080fd5b853561250a816123b2565b94506020868101359450605f8701881361252357600080fd5b61252b612460565b80608089018a81111561253d57600080fd5b60408a015b81811015612562578035612555816123b2565b8452928401928401612542565b508196506125708b82612497565b989b979a50959860c001359695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156125bd578351835292840192918401916001016125a1565b50909695505050505050565b60005b838110156125e45781810151838201526020016125cc565b50506000910152565b600081518084526126058160208601602086016125c9565b601f01601f19169290920160200192915050565b602081526000610a8860208301846125ed565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561267f57600080fd5b505080516020909101519092909150565b6000602082840312156126a257600080fd5b8151610a88816123b2565b6000602082840312156126bf57600080fd5b815160ff81168114610a8857600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b80851115612721578160001904821115612707576127076126d0565b8085161561271457918102915b93841c93908002906126eb565b509250929050565b60008261273857506001610607565b8161274557506000610607565b816001811461275b576002811461276557612781565b6001915050610607565b60ff841115612776576127766126d0565b50506001821b610607565b5060208310610133831016604e8410600b84101617156127a4575081810a610607565b6127ae83836126e6565b80600019048211156127c2576127c26126d0565b029392505050565b6000610a8860ff841683612729565b6000602082840312156127eb57600080fd5b5051919050565b81810381811115610607576106076126d0565b8082028115828204841417610607576106076126d0565b60008261283957634e487b7160e01b600052601260045260246000fd5b500490565b600060018060a01b03808916835260c0602084015261286060c08401896125ed565b9681166040840152949094166060820152608081019290925260a0909101525092915050565b80820180821115610607576106076126d0565b6000602082840312156128ab57600080fd5b81518015158114610a8857600080fd5b600080600080608085870312156128d157600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082516129038184602087016125c9565b919091019291505056fea2646970667358221220178dd84b4f7399a48227aecb116f8a764f360ed5e67c5f113f08a646580420d864736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806324a6c3201461005b57806343f8b62c146100765780634b4bd6f714610098578063d0c9e363146100c5575b600080fd5b610063600281565b6040519081526020015b60405180910390f35b81801561008257600080fd5b506100966100913660046123ca565b6100d4565b005b8180156100a457600080fd5b506100b86100b33660046124e7565b6102ac565b60405161006d9190612585565b610063670de0b6b3a764000081565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152846101225760405162461bcd60e51b81526004016101199190612619565b60405180910390fd5b5060408051808201909152601481527354532d333220746f6f20686967682076616c756560601b6020820152670de0b6b3a764000085106101765760405162461bcd60e51b81526004016101199190612619565b5061017f61230d565b6001600160a01b03808816825286166020820152604081018590526060810184905260808101839052610140810182905260006101bb8a610542565b604080516002808252606082018352929350600092909160208301908036833701905050905088816000815181106101f5576101f561262c565b60200260200101906001600160a01b031690816001600160a01b03168152505087816001815181106102295761022961262c565b60200260200101906001600160a01b031690816001600160a01b0316815250506102558282600261060d565b8460a001516000018560a00151602001829052829052505061029f8360405180604001604052808e6001600160a01b031681526020018d6001600160a01b0316815250600261080c565b5050505050505050505050565b60606102b6612394565b600060405180604001604052806102ec6102e6896000600281106102dc576102dc61262c565b6020020151610a03565b8a610a6e565b81526020016102fc8860016102dc565b90526020870151875160405163dd27ede760e01b81529293506000926001600160a01b038c169263dd27ede79261033c9230929190600190600401612642565b60408051808303816000875af115801561035a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e919061266c565b50865190915081111561048757600081891161039a578861039c565b815b6020890151895160405163954d7e7360e01b81526001600160a01b03808f1660048301529283166024820152911660448201526064810182905290915073__$e930d50fb5f4f1298547dbcb2bb0591990$__9063954d7e73906084016040805180830381865af4158015610414573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610438919061266c565b505060408051808201909152806104616104538b60006102dc565b8660005b6020020151610a6e565b815260200161047c6104748b60016102dc565b866001610457565b8152509350506104a0565b6040518060400160405280898152602001600081525092505b6104ad8984898989610a8f565b60408051600280825260608201835290916020830190803683370190505093506104e36104db8860006102dc565b836000610457565b846000815181106104f6576104f661262c565b602090810291909101015261051761050f8860016102dc565b836001610457565b8460018151811061052a5761052a61262c565b60200260200101818152505050505095945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a69190612690565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190612690565b92915050565b6060808267ffffffffffffffff8111156106295761062961244a565b604051908082528060200260200182016040528015610652578160200160208202803683370190505b5091508267ffffffffffffffff81111561066e5761066e61244a565b604051908082528060200260200182016040528015610697578160200160208202803683370190505b50905060005b83811015610803578481815181106106b7576106b761262c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072091906126ad565b61072b90600a6127ca565b82828151811061073d5761073d61262c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061076a5761076a61262c565b60200260200101516040518263ffffffff1660e01b815260040161079d91906001600160a01b0391909116815260200190565b602060405180830381865afa1580156107ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107de91906127d9565b8382815181106107f0576107f061262c565b602090810291909101015260010161069d565b50935093915050565b82516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087791906127d9565b60c084015260208301516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906127d9565b60e084015281518351602085015160405163dd27ede760e01b81526001600160a01b039093169263dd27ede792610928923092600190600401612642565b60408051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a919061266c565b5061010084015281516020840151845160405163dd27ede760e01b81526001600160a01b039093169263dd27ede7926109aa923092600190600401612642565b60408051808303816000875af11580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ec919061266c565b506101208401526109fe838383610f7f565b505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060791906127d9565b6000818311610a7e576000610a88565b610a8882846127f2565b9392505050565b610ac86040518060c001604052806060815260200160608152602001600081526020016000815260200160008152602001606081525090565b6000610ad387610542565b604080516002808252606082018352929350600092909160208301908036833750508751825192935091839150600090610b0f57610b0f61262c565b6001600160a01b0392909216602092830291909101820152860151815182906001908110610b3f57610b3f61262c565b60200260200101906001600160a01b031690816001600160a01b031681525050610b6b8282600261060d565b60208501819052908452805190925060009150610b8a57610b8a61262c565b60200260200101518160000151600081518110610ba957610ba961262c565b602002602001015186600060028110610bc457610bc461262c565b6020020151610bd39190612805565b610bdd919061281c565b6040820152602081015180516001908110610bfa57610bfa61262c565b60200260200101518160000151600181518110610c1957610c1961262c565b602002602001015186600160028110610c3457610c3461262c565b6020020151610c439190612805565b610c4d919061281c565b6060820152610c6482670de0b6b3a76400006127f2565b60808201526060810151610c79908390612805565b81608001518260400151610c8d9190612805565b1115610df55760008160800151838360600151610caa9190612805565b610cb4919061281c565b905060008260000151600081518110610ccf57610ccf61262c565b60200260200101518360200151600081518110610cee57610cee61262c565b6020026020010151838560400151610d0691906127f2565b610d109190612805565b610d1a919061281c565b9050610d2f8660005b6020020151828a6115e7565b608080840151604080516001602082015290810187905260608101919091520160408051808303601f1901815291815260a08501829052875160208901518851925163ca27d10d60e01b815273__$e930d50fb5f4f1298547dbcb2bb0591990$__9463ca27d10d94610dac948f949293909291899160040161283e565b6040805180830381865af4158015610dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dec919061266c565b50505050610f77565b818160600151610e059190612805565b81608001518260400151610e199190612805565b1015610f775760008282608001518360400151610e369190612805565b610e40919061281c565b905060008260000151600181518110610e5b57610e5b61262c565b60200260200101518360200151600181518110610e7a57610e7a61262c565b6020026020010151838560600151610e9291906127f2565b610e9c9190612805565b610ea6919061281c565b9050610eb3866001610d23565b608083810151604080516001602082015290810191909152606081018690520160408051808303601f1901815291815260a08501829052602080890151895191890151925163ca27d10d60e01b815273__$e930d50fb5f4f1298547dbcb2bb0591990$__9463ca27d10d94610f32948f9492939091899160040161283e565b6040805180830381865af4158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f72919061266c565b505050505b505050505050565b60008360a0015160200151600081518110610f9c57610f9c61262c565b60200260200101518460a0015160000151600081518110610fbf57610fbf61262c565b60200260200101518560c00151610fd69190612805565b610fe0919061281c565b905060008460a0015160200151600181518110610fff57610fff61262c565b60200260200101518560a00151600001516001815181106110225761102261262c565b60200260200101518660e001516110399190612805565b611043919061281c565b905060008560a00151602001516000815181106110625761106261262c565b60200260200101518660a00151600001516000815181106110855761108561262c565b602002602001015187610140015161109d9190612805565b6110a7919061281c565b9050806110b48385612886565b1115610f77576000816110c78486612886565b6110d191906127f2565b9050600082670de0b6b3a76400008960400151846110ef9190612805565b6110f9919061281c565b6111039190612886565b90506000670de0b6b3a76400008960400151670de0b6b3a764000061112891906127f2565b6111329085612805565b61113c919061281c565b9050858211156113915760006040518061016001604052808a81526020018b602001516001600160a01b031681526020018b600001516001600160a01b031681526020018b60400151670de0b6b3a764000061119891906127f2565b81526020018b6040015181526020018b60a00151602001516000815181106111c2576111c261262c565b60200260200101518c60a00151600001516001815181106111e5576111e561262c565b60200260200101518d60a00151602001516001815181106112085761120861262c565b60200260200101518e60a001516000015160008151811061122b5761122b61262c565b6020026020010151670de0b6b3a76400006112469190612805565b6112509190612805565b61125a919061281c565b611264919061281c565b81526020018b608001518152602001600081526020018b61014001518152602001600181526020016000815250905060648a610100015110611370576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886112ed5760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160008151811061130b5761130b61262c565b60200260200101518b60a001516020015160008151811061132e5761132e61262c565b6020026020010151898661134291906127f2565b61134c9190612805565b611356919061281c565b905061136a8b83838e61010001518d6116dc565b5061138b565b611388818b60a001518c60e001518d60c001516117a4565b50505b506115df565b858210156115df5760006040518061016001604052808a81526020018b600001516001600160a01b031681526020018b602001516001600160a01b031681526020018b6040015181526020018b60400151670de0b6b3a76400006113f591906127f2565b81526020018b60a00151602001516001815181106114155761141561262c565b60200260200101518c60a00151600001516000815181106114385761143861262c565b60200260200101518d60a001516020015160008151811061145b5761145b61262c565b60200260200101518e60a001516000015160018151811061147e5761147e61262c565b6020026020010151670de0b6b3a76400006114999190612805565b6114a39190612805565b6114ad919061281c565b6114b7919061281c565b81526020018b6060015181526020018b6101400151815260200160008152602001600081526020016001815250905060648a6101200151106115c3576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886115405760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160018151811061155e5761155e61262c565b60200260200101518b60a00151602001516001815181106115815761158161262c565b6020026020010151888561159591906127f2565b61159f9190612805565b6115a9919061281c565b90506115bd8b83838e61012001518d6116dc565b50610dec565b6115db818b60a001518c60c001518d60e001516117a4565b5050505b505050610f77565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015611636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165a91906127d9565b10156109fe5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156116b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d69190612899565b50505050565b6040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152816117295760405162461bcd60e51b81526004016101199190612619565b506000670de0b6b3a76400008560a00151856117459190612805565b61174f919061281c565b9050600061175d8285611911565b90506064811061179b578551516040870151602088015161178092919084611927565b5050865161179b915088906117966001876127f2565b61080c565b50505050505050565b6000808560e00151600014806117bd5750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118075760405162461bcd60e51b81526004016101199190612619565b50610100860151156118825785610100015183106118435761183a86858861010001518661183591906127f2565b611ae9565b91509150611908565b6000611861878787878b610100015161185c91906127f2565b611c82565b5090506118788761187283886127f2565b86611ae9565b9250925050611908565b60e0860151156118fd578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906118e25760405162461bcd60e51b81526004016101199190612619565b5061183a868760e00151866118f791906127f2565b85611ae9565b61183a868585611ae9565b94509492505050565b60008183106119205781610a88565b5090919050565b6040516370a0823160e01b81523060048201526000908190819081906001600160a01b038716906370a0823190602401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199891906127d9565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b81526004016119cf9493929190612642565b60408051808303816000875af11580156119ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a11919061266c565b509050611a2c818710611a245781611a26565b865b83611911565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab2919061266c565b909650905080861115611acc57611ac981876127f2565b95505b611ad98a8a8a8787611e8b565b9550505050509450945094915050565b606083810151608080860151604080516001602082015280820194909452838501919091528051808403909401845291019052600090819081908415611bb957670de0b6b3a7640000876080015188606001518960a0015188611b4c9190612805565b611b569190612805565b611b60919061281c565b611b6a919061281c565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b81525090611bb75760405162461bcd60e51b81526004016101199190612619565b505b6020870151611bd490611bcc84896127f2565b8951516115e7565b73__$e930d50fb5f4f1298547dbcb2bb0591990$__63ca27d10d886000015160000151838a602001518b60400151878c611c0e91906127f2565b8d60c001516040518763ffffffff1660e01b8152600401611c349695949392919061283e565b6040805180830381865af4158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061266c565b935093505050935093915050565b6000806000856020015187610140015181518110611ca257611ca261262c565b6020026020010151866000015188610120015181518110611cc557611cc561262c565b6020026020010151876020015189610120015181518110611ce857611ce861262c565b602002602001015188600001518a610140015181518110611d0b57611d0b61262c565b602002602001015187611d1e9190612805565b611d289190612805565b611d32919061281c565b611d3c919061281c565b9050620186a0611d4e61012c82612886565b611d589083612805565b611d62919061281c565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b81525090611db55760405162461bcd60e51b81526004016101199190612619565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e482015273__$e930d50fb5f4f1298547dbcb2bb0591990$__90637de8f56990610104016040805180830381865af4158015611e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7d919061266c565b909890975095505050505050565b6000806064841061206657611eaa6001600160a01b0386168886612070565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015611f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2f91906128bb565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906127d9565b905080851161201057600061201a565b61201a81866127f2565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156120625760405162461bcd60e51b81526004016101199190612619565b5050505b9550959350505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908401526109fe9286929160009161210091851690849061217d565b8051909150156109fe578080602001905181019061211e9190612899565b6109fe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610119565b606061218c8484600085612194565b949350505050565b6060824710156121f55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610119565b600080866001600160a01b0316858760405161221191906128f1565b60006040518083038185875af1925050503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b50915091506122648783838761226f565b979650505050505050565b606083156122de5782516000036122d7576001600160a01b0385163b6122d75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610119565b508161218c565b61218c83838151156122f35781518083602001fd5b8060405162461bcd60e51b81526004016101199190612619565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161236b604051806040016040528060608152602001606081525090565b815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146123c757600080fd5b50565b600080600080600080600080610100898b0312156123e757600080fd5b88356123f2816123b2565b97506020890135612402816123b2565b96506040890135612412816123b2565b95506060890135612422816123b2565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561249157634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f8301126124a857600080fd5b6124b0612460565b8060408401858111156124c257600080fd5b845b818110156124dc5780358452602093840193016124c4565b509095945050505050565b600080600080600060e086880312156124ff57600080fd5b853561250a816123b2565b94506020868101359450605f8701881361252357600080fd5b61252b612460565b80608089018a81111561253d57600080fd5b60408a015b81811015612562578035612555816123b2565b8452928401928401612542565b508196506125708b82612497565b989b979a50959860c001359695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156125bd578351835292840192918401916001016125a1565b50909695505050505050565b60005b838110156125e45781810151838201526020016125cc565b50506000910152565b600081518084526126058160208601602086016125c9565b601f01601f19169290920160200192915050565b602081526000610a8860208301846125ed565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561267f57600080fd5b505080516020909101519092909150565b6000602082840312156126a257600080fd5b8151610a88816123b2565b6000602082840312156126bf57600080fd5b815160ff81168114610a8857600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b80851115612721578160001904821115612707576127076126d0565b8085161561271457918102915b93841c93908002906126eb565b509250929050565b60008261273857506001610607565b8161274557506000610607565b816001811461275b576002811461276557612781565b6001915050610607565b60ff841115612776576127766126d0565b50506001821b610607565b5060208310610133831016604e8410600b84101617156127a4575081810a610607565b6127ae83836126e6565b80600019048211156127c2576127c26126d0565b029392505050565b6000610a8860ff841683612729565b6000602082840312156127eb57600080fd5b5051919050565b81810381811115610607576106076126d0565b8082028115828204841417610607576106076126d0565b60008261283957634e487b7160e01b600052601260045260246000fd5b500490565b600060018060a01b03808916835260c0602084015261286060c08401896125ed565b9681166040840152949094166060820152608081019290925260a0909101525092915050565b80820180821115610607576106076126d0565b6000602082840312156128ab57600080fd5b81518015158114610a8857600080fd5b600080600080608085870312156128d157600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082516129038184602087016125c9565b919091019291505056fea2646970667358221220178dd84b4f7399a48227aecb116f8a764f360ed5e67c5f113f08a646580420d864736f6c63430008110033", + "numDeployments": 16, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MAX_DEEP_RECURSION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SUM_PROPORTIONS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\",\"kind\":\"dev\",\"methods\":{\"prepareToDeposit(ITetuConverter,uint256,address[2],uint256[2],uint256)\":{\"params\":{\"amount_\":\"Amount of underlying that is going to be deposited We assume here, that current balance >= the {amount_}\",\"prop0\":\"Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\",\"thresholds_\":\"Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\",\"tokens_\":\"[Underlying, not underlying]\"},\"returns\":{\"tokenAmounts\":\"Result amounts [A0 (underlying), A1 (not-underlying)]\"}},\"rebalanceAssets(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"addition0\":\"Additional amount A0 of {asset0}. Balance0 = A0 + B0 We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\",\"prop0\":\"Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\",\"threshold0\":\"Min allowed amount of {asset0}-collateral, 0 - use default min value\",\"threshold1\":\"Min allowed amount of {asset1}-collateral, 0 - use default min value\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MAX_DEEP_RECURSION()\":{\"notice\":\"Function {_rebalanceAssets} cannot be called recursively more than twice. Normally one call is enough. Firstly repay(requiredAmount0) is called below. There are two possible results: 1) requiredCost0 <= cost0 2) v.directDebt == 0 There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected because of debt gap. So, we need second cycle.\"},\"SUM_PROPORTIONS()\":{\"notice\":\"prop0 + prop1\"},\"prepareToDeposit(ITetuConverter,uint256,address[2],uint256[2],uint256)\":{\"notice\":\"Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying) Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0} The function is able to make new borrowing and/or close exist debts.\"},\"rebalanceAssets(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\"}},\"notice\":\"Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/libs/BorrowLib.sol\":\"BorrowLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x61294361003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806324a6c3201461005b57806343f8b62c146100765780634b4bd6f714610098578063d0c9e363146100c5575b600080fd5b610063600281565b6040519081526020015b60405180910390f35b81801561008257600080fd5b506100966100913660046123ca565b6100d4565b005b8180156100a457600080fd5b506100b86100b33660046124e7565b6102ac565b60405161006d9190612585565b610063670de0b6b3a764000081565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152846101225760405162461bcd60e51b81526004016101199190612619565b60405180910390fd5b5060408051808201909152601481527354532d333220746f6f20686967682076616c756560601b6020820152670de0b6b3a764000085106101765760405162461bcd60e51b81526004016101199190612619565b5061017f61230d565b6001600160a01b03808816825286166020820152604081018590526060810184905260808101839052610140810182905260006101bb8a610542565b604080516002808252606082018352929350600092909160208301908036833701905050905088816000815181106101f5576101f561262c565b60200260200101906001600160a01b031690816001600160a01b03168152505087816001815181106102295761022961262c565b60200260200101906001600160a01b031690816001600160a01b0316815250506102558282600261060d565b8460a001516000018560a00151602001829052829052505061029f8360405180604001604052808e6001600160a01b031681526020018d6001600160a01b0316815250600261080c565b5050505050505050505050565b60606102b6612394565b600060405180604001604052806102ec6102e6896000600281106102dc576102dc61262c565b6020020151610a03565b8a610a6e565b81526020016102fc8860016102dc565b90526020870151875160405163dd27ede760e01b81529293506000926001600160a01b038c169263dd27ede79261033c9230929190600190600401612642565b60408051808303816000875af115801561035a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e919061266c565b50865190915081111561048757600081891161039a578861039c565b815b6020890151895160405163954d7e7360e01b81526001600160a01b03808f16600483015292831660248201529116604482015260648101829052909150732af59Be93d77B391Fea20322407fE46907Bf9D0E9063954d7e73906084016040805180830381865af4158015610414573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610438919061266c565b505060408051808201909152806104616104538b60006102dc565b8660005b6020020151610a6e565b815260200161047c6104748b60016102dc565b866001610457565b8152509350506104a0565b6040518060400160405280898152602001600081525092505b6104ad8984898989610a8f565b60408051600280825260608201835290916020830190803683370190505093506104e36104db8860006102dc565b836000610457565b846000815181106104f6576104f661262c565b602090810291909101015261051761050f8860016102dc565b836001610457565b8460018151811061052a5761052a61262c565b60200260200101818152505050505095945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a69190612690565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190612690565b92915050565b6060808267ffffffffffffffff8111156106295761062961244a565b604051908082528060200260200182016040528015610652578160200160208202803683370190505b5091508267ffffffffffffffff81111561066e5761066e61244a565b604051908082528060200260200182016040528015610697578160200160208202803683370190505b50905060005b83811015610803578481815181106106b7576106b761262c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072091906126ad565b61072b90600a6127ca565b82828151811061073d5761073d61262c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061076a5761076a61262c565b60200260200101516040518263ffffffff1660e01b815260040161079d91906001600160a01b0391909116815260200190565b602060405180830381865afa1580156107ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107de91906127d9565b8382815181106107f0576107f061262c565b602090810291909101015260010161069d565b50935093915050565b82516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087791906127d9565b60c084015260208301516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906127d9565b60e084015281518351602085015160405163dd27ede760e01b81526001600160a01b039093169263dd27ede792610928923092600190600401612642565b60408051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a919061266c565b5061010084015281516020840151845160405163dd27ede760e01b81526001600160a01b039093169263dd27ede7926109aa923092600190600401612642565b60408051808303816000875af11580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ec919061266c565b506101208401526109fe838383610f7f565b505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060791906127d9565b6000818311610a7e576000610a88565b610a8882846127f2565b9392505050565b610ac86040518060c001604052806060815260200160608152602001600081526020016000815260200160008152602001606081525090565b6000610ad387610542565b604080516002808252606082018352929350600092909160208301908036833750508751825192935091839150600090610b0f57610b0f61262c565b6001600160a01b0392909216602092830291909101820152860151815182906001908110610b3f57610b3f61262c565b60200260200101906001600160a01b031690816001600160a01b031681525050610b6b8282600261060d565b60208501819052908452805190925060009150610b8a57610b8a61262c565b60200260200101518160000151600081518110610ba957610ba961262c565b602002602001015186600060028110610bc457610bc461262c565b6020020151610bd39190612805565b610bdd919061281c565b6040820152602081015180516001908110610bfa57610bfa61262c565b60200260200101518160000151600181518110610c1957610c1961262c565b602002602001015186600160028110610c3457610c3461262c565b6020020151610c439190612805565b610c4d919061281c565b6060820152610c6482670de0b6b3a76400006127f2565b60808201526060810151610c79908390612805565b81608001518260400151610c8d9190612805565b1115610df55760008160800151838360600151610caa9190612805565b610cb4919061281c565b905060008260000151600081518110610ccf57610ccf61262c565b60200260200101518360200151600081518110610cee57610cee61262c565b6020026020010151838560400151610d0691906127f2565b610d109190612805565b610d1a919061281c565b9050610d2f8660005b6020020151828a6115e7565b608080840151604080516001602082015290810187905260608101919091520160408051808303601f1901815291815260a08501829052875160208901518851925163ca27d10d60e01b8152732af59Be93d77B391Fea20322407fE46907Bf9D0E9463ca27d10d94610dac948f949293909291899160040161283e565b6040805180830381865af4158015610dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dec919061266c565b50505050610f77565b818160600151610e059190612805565b81608001518260400151610e199190612805565b1015610f775760008282608001518360400151610e369190612805565b610e40919061281c565b905060008260000151600181518110610e5b57610e5b61262c565b60200260200101518360200151600181518110610e7a57610e7a61262c565b6020026020010151838560600151610e9291906127f2565b610e9c9190612805565b610ea6919061281c565b9050610eb3866001610d23565b608083810151604080516001602082015290810191909152606081018690520160408051808303601f1901815291815260a08501829052602080890151895191890151925163ca27d10d60e01b8152732af59Be93d77B391Fea20322407fE46907Bf9D0E9463ca27d10d94610f32948f9492939091899160040161283e565b6040805180830381865af4158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f72919061266c565b505050505b505050505050565b60008360a0015160200151600081518110610f9c57610f9c61262c565b60200260200101518460a0015160000151600081518110610fbf57610fbf61262c565b60200260200101518560c00151610fd69190612805565b610fe0919061281c565b905060008460a0015160200151600181518110610fff57610fff61262c565b60200260200101518560a00151600001516001815181106110225761102261262c565b60200260200101518660e001516110399190612805565b611043919061281c565b905060008560a00151602001516000815181106110625761106261262c565b60200260200101518660a00151600001516000815181106110855761108561262c565b602002602001015187610140015161109d9190612805565b6110a7919061281c565b9050806110b48385612886565b1115610f77576000816110c78486612886565b6110d191906127f2565b9050600082670de0b6b3a76400008960400151846110ef9190612805565b6110f9919061281c565b6111039190612886565b90506000670de0b6b3a76400008960400151670de0b6b3a764000061112891906127f2565b6111329085612805565b61113c919061281c565b9050858211156113915760006040518061016001604052808a81526020018b602001516001600160a01b031681526020018b600001516001600160a01b031681526020018b60400151670de0b6b3a764000061119891906127f2565b81526020018b6040015181526020018b60a00151602001516000815181106111c2576111c261262c565b60200260200101518c60a00151600001516001815181106111e5576111e561262c565b60200260200101518d60a00151602001516001815181106112085761120861262c565b60200260200101518e60a001516000015160008151811061122b5761122b61262c565b6020026020010151670de0b6b3a76400006112469190612805565b6112509190612805565b61125a919061281c565b611264919061281c565b81526020018b608001518152602001600081526020018b61014001518152602001600181526020016000815250905060648a610100015110611370576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886112ed5760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160008151811061130b5761130b61262c565b60200260200101518b60a001516020015160008151811061132e5761132e61262c565b6020026020010151898661134291906127f2565b61134c9190612805565b611356919061281c565b905061136a8b83838e61010001518d6116dc565b5061138b565b611388818b60a001518c60e001518d60c001516117a4565b50505b506115df565b858210156115df5760006040518061016001604052808a81526020018b600001516001600160a01b031681526020018b602001516001600160a01b031681526020018b6040015181526020018b60400151670de0b6b3a76400006113f591906127f2565b81526020018b60a00151602001516001815181106114155761141561262c565b60200260200101518c60a00151600001516000815181106114385761143861262c565b60200260200101518d60a001516020015160008151811061145b5761145b61262c565b60200260200101518e60a001516000015160018151811061147e5761147e61262c565b6020026020010151670de0b6b3a76400006114999190612805565b6114a39190612805565b6114ad919061281c565b6114b7919061281c565b81526020018b6060015181526020018b6101400151815260200160008152602001600081526020016001815250905060648a6101200151106115c3576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886115405760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160018151811061155e5761155e61262c565b60200260200101518b60a00151602001516001815181106115815761158161262c565b6020026020010151888561159591906127f2565b61159f9190612805565b6115a9919061281c565b90506115bd8b83838e61012001518d6116dc565b50610dec565b6115db818b60a001518c60c001518d60e001516117a4565b5050505b505050610f77565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015611636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165a91906127d9565b10156109fe5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156116b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d69190612899565b50505050565b6040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152816117295760405162461bcd60e51b81526004016101199190612619565b506000670de0b6b3a76400008560a00151856117459190612805565b61174f919061281c565b9050600061175d8285611911565b90506064811061179b578551516040870151602088015161178092919084611927565b5050865161179b915088906117966001876127f2565b61080c565b50505050505050565b6000808560e00151600014806117bd5750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118075760405162461bcd60e51b81526004016101199190612619565b50610100860151156118825785610100015183106118435761183a86858861010001518661183591906127f2565b611ae9565b91509150611908565b6000611861878787878b610100015161185c91906127f2565b611c82565b5090506118788761187283886127f2565b86611ae9565b9250925050611908565b60e0860151156118fd578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906118e25760405162461bcd60e51b81526004016101199190612619565b5061183a868760e00151866118f791906127f2565b85611ae9565b61183a868585611ae9565b94509492505050565b60008183106119205781610a88565b5090919050565b6040516370a0823160e01b81523060048201526000908190819081906001600160a01b038716906370a0823190602401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199891906127d9565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b81526004016119cf9493929190612642565b60408051808303816000875af11580156119ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a11919061266c565b509050611a2c818710611a245781611a26565b865b83611911565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab2919061266c565b909650905080861115611acc57611ac981876127f2565b95505b611ad98a8a8a8787611e8b565b9550505050509450945094915050565b606083810151608080860151604080516001602082015280820194909452838501919091528051808403909401845291019052600090819081908415611bb957670de0b6b3a7640000876080015188606001518960a0015188611b4c9190612805565b611b569190612805565b611b60919061281c565b611b6a919061281c565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b81525090611bb75760405162461bcd60e51b81526004016101199190612619565b505b6020870151611bd490611bcc84896127f2565b8951516115e7565b732af59Be93d77B391Fea20322407fE46907Bf9D0E63ca27d10d886000015160000151838a602001518b60400151878c611c0e91906127f2565b8d60c001516040518763ffffffff1660e01b8152600401611c349695949392919061283e565b6040805180830381865af4158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061266c565b935093505050935093915050565b6000806000856020015187610140015181518110611ca257611ca261262c565b6020026020010151866000015188610120015181518110611cc557611cc561262c565b6020026020010151876020015189610120015181518110611ce857611ce861262c565b602002602001015188600001518a610140015181518110611d0b57611d0b61262c565b602002602001015187611d1e9190612805565b611d289190612805565b611d32919061281c565b611d3c919061281c565b9050620186a0611d4e61012c82612886565b611d589083612805565b611d62919061281c565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b81525090611db55760405162461bcd60e51b81526004016101199190612619565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e4820152732af59Be93d77B391Fea20322407fE46907Bf9D0E90637de8f56990610104016040805180830381865af4158015611e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7d919061266c565b909890975095505050505050565b6000806064841061206657611eaa6001600160a01b0386168886612070565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015611f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2f91906128bb565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906127d9565b905080851161201057600061201a565b61201a81866127f2565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156120625760405162461bcd60e51b81526004016101199190612619565b5050505b9550959350505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908401526109fe9286929160009161210091851690849061217d565b8051909150156109fe578080602001905181019061211e9190612899565b6109fe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610119565b606061218c8484600085612194565b949350505050565b6060824710156121f55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610119565b600080866001600160a01b0316858760405161221191906128f1565b60006040518083038185875af1925050503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b50915091506122648783838761226f565b979650505050505050565b606083156122de5782516000036122d7576001600160a01b0385163b6122d75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610119565b508161218c565b61218c83838151156122f35781518083602001fd5b8060405162461bcd60e51b81526004016101199190612619565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161236b604051806040016040528060608152602001606081525090565b815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146123c757600080fd5b50565b600080600080600080600080610100898b0312156123e757600080fd5b88356123f2816123b2565b97506020890135612402816123b2565b96506040890135612412816123b2565b95506060890135612422816123b2565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561249157634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f8301126124a857600080fd5b6124b0612460565b8060408401858111156124c257600080fd5b845b818110156124dc5780358452602093840193016124c4565b509095945050505050565b600080600080600060e086880312156124ff57600080fd5b853561250a816123b2565b94506020868101359450605f8701881361252357600080fd5b61252b612460565b80608089018a81111561253d57600080fd5b60408a015b81811015612562578035612555816123b2565b8452928401928401612542565b508196506125708b82612497565b989b979a50959860c001359695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156125bd578351835292840192918401916001016125a1565b50909695505050505050565b60005b838110156125e45781810151838201526020016125cc565b50506000910152565b600081518084526126058160208601602086016125c9565b601f01601f19169290920160200192915050565b602081526000610a8860208301846125ed565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561267f57600080fd5b505080516020909101519092909150565b6000602082840312156126a257600080fd5b8151610a88816123b2565b6000602082840312156126bf57600080fd5b815160ff81168114610a8857600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b80851115612721578160001904821115612707576127076126d0565b8085161561271457918102915b93841c93908002906126eb565b509250929050565b60008261273857506001610607565b8161274557506000610607565b816001811461275b576002811461276557612781565b6001915050610607565b60ff841115612776576127766126d0565b50506001821b610607565b5060208310610133831016604e8410600b84101617156127a4575081810a610607565b6127ae83836126e6565b80600019048211156127c2576127c26126d0565b029392505050565b6000610a8860ff841683612729565b6000602082840312156127eb57600080fd5b5051919050565b81810381811115610607576106076126d0565b8082028115828204841417610607576106076126d0565b60008261283957634e487b7160e01b600052601260045260246000fd5b500490565b600060018060a01b03808916835260c0602084015261286060c08401896125ed565b9681166040840152949094166060820152608081019290925260a0909101525092915050565b80820180821115610607576106076126d0565b6000602082840312156128ab57600080fd5b81518015158114610a8857600080fd5b600080600080608085870312156128d157600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082516129038184602087016125c9565b919091019291505056fea2646970667358221220fde11cdb2a43cdfcd2ea988c1d0f7bc9303505afd14d6f0c6429fc168e0cab8764736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806324a6c3201461005b57806343f8b62c146100765780634b4bd6f714610098578063d0c9e363146100c5575b600080fd5b610063600281565b6040519081526020015b60405180910390f35b81801561008257600080fd5b506100966100913660046123ca565b6100d4565b005b8180156100a457600080fd5b506100b86100b33660046124e7565b6102ac565b60405161006d9190612585565b610063670de0b6b3a764000081565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152846101225760405162461bcd60e51b81526004016101199190612619565b60405180910390fd5b5060408051808201909152601481527354532d333220746f6f20686967682076616c756560601b6020820152670de0b6b3a764000085106101765760405162461bcd60e51b81526004016101199190612619565b5061017f61230d565b6001600160a01b03808816825286166020820152604081018590526060810184905260808101839052610140810182905260006101bb8a610542565b604080516002808252606082018352929350600092909160208301908036833701905050905088816000815181106101f5576101f561262c565b60200260200101906001600160a01b031690816001600160a01b03168152505087816001815181106102295761022961262c565b60200260200101906001600160a01b031690816001600160a01b0316815250506102558282600261060d565b8460a001516000018560a00151602001829052829052505061029f8360405180604001604052808e6001600160a01b031681526020018d6001600160a01b0316815250600261080c565b5050505050505050505050565b60606102b6612394565b600060405180604001604052806102ec6102e6896000600281106102dc576102dc61262c565b6020020151610a03565b8a610a6e565b81526020016102fc8860016102dc565b90526020870151875160405163dd27ede760e01b81529293506000926001600160a01b038c169263dd27ede79261033c9230929190600190600401612642565b60408051808303816000875af115801561035a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061037e919061266c565b50865190915081111561048757600081891161039a578861039c565b815b6020890151895160405163954d7e7360e01b81526001600160a01b03808f1660048301529283166024820152911660448201526064810182905290915073__$e930d50fb5f4f1298547dbcb2bb0591990$__9063954d7e73906084016040805180830381865af4158015610414573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610438919061266c565b505060408051808201909152806104616104538b60006102dc565b8660005b6020020151610a6e565b815260200161047c6104748b60016102dc565b866001610457565b8152509350506104a0565b6040518060400160405280898152602001600081525092505b6104ad8984898989610a8f565b60408051600280825260608201835290916020830190803683370190505093506104e36104db8860006102dc565b836000610457565b846000815181106104f6576104f661262c565b602090810291909101015261051761050f8860016102dc565b836001610457565b8460018151811061052a5761052a61262c565b60200260200101818152505050505095945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015610582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a69190612690565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106079190612690565b92915050565b6060808267ffffffffffffffff8111156106295761062961244a565b604051908082528060200260200182016040528015610652578160200160208202803683370190505b5091508267ffffffffffffffff81111561066e5761066e61244a565b604051908082528060200260200182016040528015610697578160200160208202803683370190505b50905060005b83811015610803578481815181106106b7576106b761262c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072091906126ad565b61072b90600a6127ca565b82828151811061073d5761073d61262c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061076a5761076a61262c565b60200260200101516040518263ffffffff1660e01b815260040161079d91906001600160a01b0391909116815260200190565b602060405180830381865afa1580156107ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107de91906127d9565b8382815181106107f0576107f061262c565b602090810291909101015260010161069d565b50935093915050565b82516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610853573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087791906127d9565b60c084015260208301516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea91906127d9565b60e084015281518351602085015160405163dd27ede760e01b81526001600160a01b039093169263dd27ede792610928923092600190600401612642565b60408051808303816000875af1158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a919061266c565b5061010084015281516020840151845160405163dd27ede760e01b81526001600160a01b039093169263dd27ede7926109aa923092600190600401612642565b60408051808303816000875af11580156109c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ec919061266c565b506101208401526109fe838383610f7f565b505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060791906127d9565b6000818311610a7e576000610a88565b610a8882846127f2565b9392505050565b610ac86040518060c001604052806060815260200160608152602001600081526020016000815260200160008152602001606081525090565b6000610ad387610542565b604080516002808252606082018352929350600092909160208301908036833750508751825192935091839150600090610b0f57610b0f61262c565b6001600160a01b0392909216602092830291909101820152860151815182906001908110610b3f57610b3f61262c565b60200260200101906001600160a01b031690816001600160a01b031681525050610b6b8282600261060d565b60208501819052908452805190925060009150610b8a57610b8a61262c565b60200260200101518160000151600081518110610ba957610ba961262c565b602002602001015186600060028110610bc457610bc461262c565b6020020151610bd39190612805565b610bdd919061281c565b6040820152602081015180516001908110610bfa57610bfa61262c565b60200260200101518160000151600181518110610c1957610c1961262c565b602002602001015186600160028110610c3457610c3461262c565b6020020151610c439190612805565b610c4d919061281c565b6060820152610c6482670de0b6b3a76400006127f2565b60808201526060810151610c79908390612805565b81608001518260400151610c8d9190612805565b1115610df55760008160800151838360600151610caa9190612805565b610cb4919061281c565b905060008260000151600081518110610ccf57610ccf61262c565b60200260200101518360200151600081518110610cee57610cee61262c565b6020026020010151838560400151610d0691906127f2565b610d109190612805565b610d1a919061281c565b9050610d2f8660005b6020020151828a6115e7565b608080840151604080516001602082015290810187905260608101919091520160408051808303601f1901815291815260a08501829052875160208901518851925163ca27d10d60e01b815273__$e930d50fb5f4f1298547dbcb2bb0591990$__9463ca27d10d94610dac948f949293909291899160040161283e565b6040805180830381865af4158015610dc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dec919061266c565b50505050610f77565b818160600151610e059190612805565b81608001518260400151610e199190612805565b1015610f775760008282608001518360400151610e369190612805565b610e40919061281c565b905060008260000151600181518110610e5b57610e5b61262c565b60200260200101518360200151600181518110610e7a57610e7a61262c565b6020026020010151838560600151610e9291906127f2565b610e9c9190612805565b610ea6919061281c565b9050610eb3866001610d23565b608083810151604080516001602082015290810191909152606081018690520160408051808303601f1901815291815260a08501829052602080890151895191890151925163ca27d10d60e01b815273__$e930d50fb5f4f1298547dbcb2bb0591990$__9463ca27d10d94610f32948f9492939091899160040161283e565b6040805180830381865af4158015610f4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f72919061266c565b505050505b505050505050565b60008360a0015160200151600081518110610f9c57610f9c61262c565b60200260200101518460a0015160000151600081518110610fbf57610fbf61262c565b60200260200101518560c00151610fd69190612805565b610fe0919061281c565b905060008460a0015160200151600181518110610fff57610fff61262c565b60200260200101518560a00151600001516001815181106110225761102261262c565b60200260200101518660e001516110399190612805565b611043919061281c565b905060008560a00151602001516000815181106110625761106261262c565b60200260200101518660a00151600001516000815181106110855761108561262c565b602002602001015187610140015161109d9190612805565b6110a7919061281c565b9050806110b48385612886565b1115610f77576000816110c78486612886565b6110d191906127f2565b9050600082670de0b6b3a76400008960400151846110ef9190612805565b6110f9919061281c565b6111039190612886565b90506000670de0b6b3a76400008960400151670de0b6b3a764000061112891906127f2565b6111329085612805565b61113c919061281c565b9050858211156113915760006040518061016001604052808a81526020018b602001516001600160a01b031681526020018b600001516001600160a01b031681526020018b60400151670de0b6b3a764000061119891906127f2565b81526020018b6040015181526020018b60a00151602001516000815181106111c2576111c261262c565b60200260200101518c60a00151600001516001815181106111e5576111e561262c565b60200260200101518d60a00151602001516001815181106112085761120861262c565b60200260200101518e60a001516000015160008151811061122b5761122b61262c565b6020026020010151670de0b6b3a76400006112469190612805565b6112509190612805565b61125a919061281c565b611264919061281c565b81526020018b608001518152602001600081526020018b61014001518152602001600181526020016000815250905060648a610100015110611370576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886112ed5760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160008151811061130b5761130b61262c565b60200260200101518b60a001516020015160008151811061132e5761132e61262c565b6020026020010151898661134291906127f2565b61134c9190612805565b611356919061281c565b905061136a8b83838e61010001518d6116dc565b5061138b565b611388818b60a001518c60e001518d60c001516117a4565b50505b506115df565b858210156115df5760006040518061016001604052808a81526020018b600001516001600160a01b031681526020018b602001516001600160a01b031681526020018b6040015181526020018b60400151670de0b6b3a76400006113f591906127f2565b81526020018b60a00151602001516001815181106114155761141561262c565b60200260200101518c60a00151600001516000815181106114385761143861262c565b60200260200101518d60a001516020015160008151811061145b5761145b61262c565b60200260200101518e60a001516000015160018151811061147e5761147e61262c565b6020026020010151670de0b6b3a76400006114999190612805565b6114a39190612805565b6114ad919061281c565b6114b7919061281c565b81526020018b6060015181526020018b6101400151815260200160008152602001600081526020016001815250905060648a6101200151106115c3576040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152886115405760405162461bcd60e51b81526004016101199190612619565b5060008a60a001516000015160018151811061155e5761155e61262c565b60200260200101518b60a00151602001516001815181106115815761158161262c565b6020026020010151888561159591906127f2565b61159f9190612805565b6115a9919061281c565b90506115bd8b83838e61012001518d6116dc565b50610dec565b6115db818b60a001518c60c001518d60e001516117a4565b5050505b505050610f77565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015611636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165a91906127d9565b10156109fe5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156116b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d69190612899565b50505050565b6040805180820190915260188152772a29969999903a37b7903232b2b8103932b1bab939b4b7b760411b6020820152816117295760405162461bcd60e51b81526004016101199190612619565b506000670de0b6b3a76400008560a00151856117459190612805565b61174f919061281c565b9050600061175d8285611911565b90506064811061179b578551516040870151602088015161178092919084611927565b5050865161179b915088906117966001876127f2565b61080c565b50505050505050565b6000808560e00151600014806117bd5750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118075760405162461bcd60e51b81526004016101199190612619565b50610100860151156118825785610100015183106118435761183a86858861010001518661183591906127f2565b611ae9565b91509150611908565b6000611861878787878b610100015161185c91906127f2565b611c82565b5090506118788761187283886127f2565b86611ae9565b9250925050611908565b60e0860151156118fd578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906118e25760405162461bcd60e51b81526004016101199190612619565b5061183a868760e00151866118f791906127f2565b85611ae9565b61183a868585611ae9565b94509492505050565b60008183106119205781610a88565b5090919050565b6040516370a0823160e01b81523060048201526000908190819081906001600160a01b038716906370a0823190602401602060405180830381865afa158015611974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199891906127d9565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b81526004016119cf9493929190612642565b60408051808303816000875af11580156119ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a11919061266c565b509050611a2c818710611a245781611a26565b865b83611911565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab2919061266c565b909650905080861115611acc57611ac981876127f2565b95505b611ad98a8a8a8787611e8b565b9550505050509450945094915050565b606083810151608080860151604080516001602082015280820194909452838501919091528051808403909401845291019052600090819081908415611bb957670de0b6b3a7640000876080015188606001518960a0015188611b4c9190612805565b611b569190612805565b611b60919061281c565b611b6a919061281c565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b81525090611bb75760405162461bcd60e51b81526004016101199190612619565b505b6020870151611bd490611bcc84896127f2565b8951516115e7565b73__$e930d50fb5f4f1298547dbcb2bb0591990$__63ca27d10d886000015160000151838a602001518b60400151878c611c0e91906127f2565b8d60c001516040518763ffffffff1660e01b8152600401611c349695949392919061283e565b6040805180830381865af4158015611c50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c74919061266c565b935093505050935093915050565b6000806000856020015187610140015181518110611ca257611ca261262c565b6020026020010151866000015188610120015181518110611cc557611cc561262c565b6020026020010151876020015189610120015181518110611ce857611ce861262c565b602002602001015188600001518a610140015181518110611d0b57611d0b61262c565b602002602001015187611d1e9190612805565b611d289190612805565b611d32919061281c565b611d3c919061281c565b9050620186a0611d4e61012c82612886565b611d589083612805565b611d62919061281c565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b81525090611db55760405162461bcd60e51b81526004016101199190612619565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e482015273__$e930d50fb5f4f1298547dbcb2bb0591990$__90637de8f56990610104016040805180830381865af4158015611e59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7d919061266c565b909890975095505050505050565b6000806064841061206657611eaa6001600160a01b0386168886612070565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015611f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2f91906128bb565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81523060048201526000906001600160a01b038816906370a0823190602401602060405180830381865afa158015611fdc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200091906127d9565b905080851161201057600061201a565b61201a81866127f2565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156120625760405162461bcd60e51b81526004016101199190612619565b5050505b9550959350505050565b604080516001600160a01b03848116602483015260448083018590528351808403909101815260649092018352602080830180516001600160e01b031663a9059cbb60e01b17905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908401526109fe9286929160009161210091851690849061217d565b8051909150156109fe578080602001905181019061211e9190612899565b6109fe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610119565b606061218c8484600085612194565b949350505050565b6060824710156121f55760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610119565b600080866001600160a01b0316858760405161221191906128f1565b60006040518083038185875af1925050503d806000811461224e576040519150601f19603f3d011682016040523d82523d6000602084013e612253565b606091505b50915091506122648783838761226f565b979650505050505050565b606083156122de5782516000036122d7576001600160a01b0385163b6122d75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610119565b508161218c565b61218c83838151156122f35781518083602001fd5b8060405162461bcd60e51b81526004016101199190612619565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200161236b604051806040016040528060608152602001606081525090565b815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146123c757600080fd5b50565b600080600080600080600080610100898b0312156123e757600080fd5b88356123f2816123b2565b97506020890135612402816123b2565b96506040890135612412816123b2565b95506060890135612422816123b2565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561249157634e487b7160e01b600052604160045260246000fd5b60405290565b600082601f8301126124a857600080fd5b6124b0612460565b8060408401858111156124c257600080fd5b845b818110156124dc5780358452602093840193016124c4565b509095945050505050565b600080600080600060e086880312156124ff57600080fd5b853561250a816123b2565b94506020868101359450605f8701881361252357600080fd5b61252b612460565b80608089018a81111561253d57600080fd5b60408a015b81811015612562578035612555816123b2565b8452928401928401612542565b508196506125708b82612497565b989b979a50959860c001359695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156125bd578351835292840192918401916001016125a1565b50909695505050505050565b60005b838110156125e45781810151838201526020016125cc565b50506000910152565b600081518084526126058160208601602086016125c9565b601f01601f19169290920160200192915050565b602081526000610a8860208301846125ed565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561267f57600080fd5b505080516020909101519092909150565b6000602082840312156126a257600080fd5b8151610a88816123b2565b6000602082840312156126bf57600080fd5b815160ff81168114610a8857600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b80851115612721578160001904821115612707576127076126d0565b8085161561271457918102915b93841c93908002906126eb565b509250929050565b60008261273857506001610607565b8161274557506000610607565b816001811461275b576002811461276557612781565b6001915050610607565b60ff841115612776576127766126d0565b50506001821b610607565b5060208310610133831016604e8410600b84101617156127a4575081810a610607565b6127ae83836126e6565b80600019048211156127c2576127c26126d0565b029392505050565b6000610a8860ff841683612729565b6000602082840312156127eb57600080fd5b5051919050565b81810381811115610607576106076126d0565b8082028115828204841417610607576106076126d0565b60008261283957634e487b7160e01b600052601260045260246000fd5b500490565b600060018060a01b03808916835260c0602084015261286060c08401896125ed565b9681166040840152949094166060820152608081019290925260a0909101525092915050565b80820180821115610607576106076126d0565b6000602082840312156128ab57600080fd5b81518015158114610a8857600080fd5b600080600080608085870312156128d157600080fd5b505082516020840151604085015160609095015191969095509092509050565b600082516129038184602087016125c9565b919091019291505056fea2646970667358221220fde11cdb2a43cdfcd2ea988c1d0f7bc9303505afd14d6f0c6429fc168e0cab8764736f6c63430008110033", "libraries": { - "ConverterStrategyBaseLib": "0x0Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1" + "ConverterStrategyBaseLib": "0x2af59Be93d77B391Fea20322407fE46907Bf9D0E" }, "devdoc": { "details": "Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small", diff --git a/deployments/matic/ConverterStrategyBaseLib.json b/deployments/matic/ConverterStrategyBaseLib.json index 558a0584..16778871 100644 --- a/deployments/matic/ConverterStrategyBaseLib.json +++ b/deployments/matic/ConverterStrategyBaseLib.json @@ -1,5 +1,5 @@ { - "address": "0x0Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1", + "address": "0x2af59Be93d77B391Fea20322407fE46907Bf9D0E", "abi": [ { "anonymous": false, @@ -225,44 +225,44 @@ "type": "event" } ], - "transactionHash": "0x5aa7a159c0c7eb2d04710c4c4d35609747513bf5acf8867627a27a998148a141", + "transactionHash": "0xdb3666ebaefb7daeace7694ea803202254575f33295e9bbf6c21d43a3c68d021", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0x0Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1", - "transactionIndex": 176, - "gasUsed": "4315859", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0x08a0f1141ec7bb2023ff1379935682aaeefa039c26f0b588414e37d0a8b566c5", - "transactionHash": "0x5aa7a159c0c7eb2d04710c4c4d35609747513bf5acf8867627a27a998148a141", + "contractAddress": "0x2af59Be93d77B391Fea20322407fE46907Bf9D0E", + "transactionIndex": 10, + "gasUsed": "4369054", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000800000000000000000000000000000800000000000000000000100000000000100000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000040001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0xd97f814936afe22c5c38140a12a48d3bc610dc99aed19a4d30d14f5bc6081999", + "transactionHash": "0xdb3666ebaefb7daeace7694ea803202254575f33295e9bbf6c21d43a3c68d021", "logs": [ { - "transactionIndex": 176, - "blockNumber": 54802398, - "transactionHash": "0x5aa7a159c0c7eb2d04710c4c4d35609747513bf5acf8867627a27a998148a141", + "transactionIndex": 10, + "blockNumber": 55572307, + "transactionHash": "0xdb3666ebaefb7daeace7694ea803202254575f33295e9bbf6c21d43a3c68d021", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x000000000000000000000000b95d435df3f8b2a8d8b9c2b7c8766c9ae6ed8cc9" ], - "data": "0x0000000000000000000000000000000000000000000000000016ffe057e4bd0000000000000000000000000000000000000000000000000270aee6cb31a2b86a000000000000000000000000000000000000000000002433be0f81a8de1378fc0000000000000000000000000000000000000000000000027097e6ead9bdfb6a000000000000000000000000000000000000000000002433be26818935f835fc", - "logIndex": 541, - "blockHash": "0x08a0f1141ec7bb2023ff1379935682aaeefa039c26f0b588414e37d0a8b566c5" + "data": "0x00000000000000000000000000000000000000000000000002e3257ec717c9fa000000000000000000000000000000000000000000000001ea56a7eb570323ec000000000000000000000000000000000000000000000013e5ec93af491764fa000000000000000000000000000000000000000000000001e773826c8feb59f2000000000000000000000000000000000000000000000013e8cfb92e102f2ef4", + "logIndex": 27, + "blockHash": "0xd97f814936afe22c5c38140a12a48d3bc610dc99aed19a4d30d14f5bc6081999" } ], - "blockNumber": 54802398, - "cumulativeGasUsed": "26768817", + "blockNumber": 55572307, + "cumulativeGasUsed": "4903931", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 27, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrowAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountRepay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recepient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"returnedAssetAmountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"returnedBorrowAmountOut\",\"type\":\"uint256\"}],\"name\":\"ClosePosition\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenIn\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenOut\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"spentAmountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"receivedAmountOut\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"debtToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtLeftovers\",\"type\":\"int256\"}],\"name\":\"OnCoverDebtToInsurance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtToInsuranceBefore\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtToInsuraneAfter\",\"type\":\"int256\"}],\"name\":\"OnPayDebtToInsurance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"converter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrowAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recepient\",\"type\":\"address\"}],\"name\":\"OpenPosition\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"rewardTokens\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amountsToForward\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toPerf\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toInsurance\",\"type\":\"uint256\"}],\"name\":\"Recycle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ReturnAssetToConverter\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"OnCoverDebtToInsurance(address,uint256,uint256,int256)\":{\"params\":{\"debtLeftovers\":\"Final amount of debt that should be covered, in underlying It can be negative if we paid more than required\",\"debtToCover\":\"Initial amount of debt that should be covered, in underlying\"}},\"OnPayDebtToInsurance(int256,int256)\":{\"params\":{\"debtToInsuranceBefore\":\"Final amount of debts to the insurance, in underlying\"}},\"Recycle(address[],uint256[],uint256,uint256)\":{\"params\":{\"amountsToForward\":\"Amounts to be sent to forwarder\",\"rewardTokens\":\"Full list of reward tokens received from tetuConverter and depositor\"}}},\"kind\":\"dev\",\"methods\":{\"beforeDeposit(ITetuConverter,uint256,address[],uint256,uint256[],uint256,mapping(address => uint256) storage)\":{\"params\":{\"amount_\":\"Amount of underlying to be deposited\",\"indexAsset_\":\"Index of main {asset} in {tokens}\",\"tokens_\":\"Tokens received from {_depositorPoolAssets}\",\"totalWeight_\":\"Sum of {weights_}\",\"weights_\":\"Depositor pool weights\"}},\"closePosition(ITetuConverter,address,address,uint256)\":{\"params\":{\"amountToRepay\":\"Amount to repay in terms of {borrowAsset}\"},\"returns\":{\"repaidAmountOut\":\"Amount that was actually repaid\",\"returnedAssetAmountOut\":\"Amount of collateral received back after repaying\"}},\"closePositionsToGetAmount(ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage,uint256,address[])\":{\"details\":\"We assume here that this function is called before closing any positions in the current block\",\"params\":{\"liquidationThresholds\":\"Min allowed amounts-out for liquidations\",\"requestedBalance\":\"Total amount of the given asset that we need to have on balance at the end. Max uint means attempt to withdraw all possible amount.\"},\"returns\":{\"expectedBalance\":\"Expected asset balance after all swaps and repays\"}},\"liquidate(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,bool)\":{\"params\":{\"liquidationThresholdForTokenIn_\":\"Liquidation threshold for {amountIn_}\",\"skipValidation\":\"Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\"},\"returns\":{\"receivedAmountOut\":\"Amount of {tokenOut_} has been returned by the liquidator\",\"spentAmountIn\":\"Amount of {tokenIn} has been consumed by the liquidator\"}},\"makeRequestedAmount(address[],uint256,ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage)\":{\"params\":{\"indexAsset_\":\"Index of the given {asset} in {tokens}\",\"requestedBalance\":\"Total amount of the given asset that we need to have on balance at the end. Max uint means attempt to withdraw all possible amount.\",\"tokens_\":\"Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\"},\"returns\":{\"expectedBalance\":\"Expected asset balance after all swaps and repays\"}},\"openPosition(ITetuConverter,bytes,address,address,uint256,uint256)\":{\"params\":{\"amountIn_\":\"Meaning depends on {entryData_}.\",\"entryData_\":\"Encoded entry kind and additional params if necessary (set of params depends on the kind) See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\"}},\"recycle(IStrategyV3.BaseState storage,IConverterStrategyBase.ConverterStrategyBaseState storage,address[],address,mapping(address => uint256) storage,address[],uint256[])\":{\"details\":\"{_recycle} is implemented as separate (inline) function to simplify unit testing\",\"params\":{\"rewardAmounts_\":\"Amounts of {rewardTokens_}; we assume, there are no zero amounts here\",\"rewardTokens_\":\"Full list of reward tokens received from tetuConverter and depositor\"},\"returns\":{\"amountPerf\":\"Performance fee in terms of underlying\",\"paidDebtToInsurance\":\"Earned amount spent on debt-to-insurance payment\"}}},\"version\":1},\"userdoc\":{\"events\":{\"ClosePosition(address,address,uint256,address,uint256,uint256)\":{\"notice\":\"Some borrow(s) was/were repaid\"},\"Liquidation(address,address,uint256,uint256,uint256)\":{\"notice\":\"A liquidation was made\"},\"OnCoverDebtToInsurance(address,uint256,uint256,int256)\":{\"notice\":\"Debt to insurance was paid by a reward token\"},\"OnPayDebtToInsurance(int256,int256)\":{\"notice\":\"Debt to insurance was paid by rewards\"},\"OpenPosition(address,address,uint256,address,uint256,address)\":{\"notice\":\"A borrow was made\"},\"Recycle(address[],uint256[],uint256,uint256)\":{\"notice\":\"Recycle was made\"}},\"kind\":\"user\",\"methods\":{\"beforeDeposit(ITetuConverter,uint256,address[],uint256,uint256[],uint256,mapping(address => uint256) storage)\":{\"notice\":\"Default implementation of ConverterStrategyBase.beforeDeposit\"},\"closePosition(ITetuConverter,address,address,uint256)\":{\"notice\":\"Close the given position, pay {amountToRepay}, return collateral amount in result\"},\"closePositionsToGetAmount(ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage,uint256,address[])\":{\"notice\":\"Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\"},\"liquidate(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,bool)\":{\"notice\":\"Make liquidation if estimated amountOut exceeds the given threshold\"},\"makeRequestedAmount(address[],uint256,ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage)\":{\"notice\":\"Convert {amountsToConvert_} to the given {asset} Swap leftovers (if any) to the given asset. If result amount is less than expected, try to close any other available debts (1 repay per block only)\"},\"openPosition(ITetuConverter,bytes,address,address,uint256,uint256)\":{\"notice\":\"Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_} Max possible collateral should be approved before calling of this function.\"},\"recycle(IStrategyV3.BaseState storage,IConverterStrategyBase.ConverterStrategyBaseState storage,address[],address,mapping(address => uint256) storage,address[],uint256[])\":{\"notice\":\"Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder. We have two kinds of rewards: 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets) 2) any other rewards All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound Compound-part of Rewards-2 can be liquidated Compound part of Rewards-1 should be just left on the balance Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance. All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/ConverterStrategyBaseLib.sol\":\"ConverterStrategyBaseLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x614d1461003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c80633542989d1461007c57806358b54f16146100b25780635dcb6130146100e05780637de8f56914610115578063954d7e7314610135578063c432aee114610155578063ca27d10d14610175575b600080fd5b81801561008857600080fd5b5061009c610097366004613fdb565b610195565b6040516100a991906140b2565b60405180910390f35b8180156100be57600080fd5b506100d26100cd3660046140c5565b61020d565b6040519081526020016100a9565b8180156100ec57600080fd5b506101006100fb366004614142565b610261565b604080519283526020830191909152016100a9565b81801561012157600080fd5b50610100610130366004614209565b610548565b81801561014157600080fd5b50610100610150366004614297565b61056d565b81801561016157600080fd5b506100d26101703660046142e8565b610589565b81801561018157600080fd5b5061010061019036600461438c565b6105ea565b60606101ad87878686896101a88e61060b565b6106d6565b9050610201888787846101fc8760008d8d815181106101ce576101ce61444c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205461091a565b610932565b98975050505050505050565b600080825190506102016040518060a001604052808a6001600160a01b03168152602001896001600160a01b031681526020018581526020018881526020018381525061025b878685610b95565b86610c2b565b6000806102cc60405180610140016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016060815260200160608152602001600081526020016000815260200160006001600160a01b031681525090565b89546001600160a01b0316815260058a0154602082015260038a0154604082015284516102fc9087908790610b95565b60c0820152600389015460e08201526001808b01546001600160a01b03908116610120840152604080516101808101909152918b01541681526103ed90602081016103468a6115e9565b6001600160a01b031681526020018361012001516001600160a01b0316815260200183600001516001600160a01b03168152602001836020015181526020018a81526020018360c001518152602001878152602001868152602001836040015181526020018360e0015181526020016103e689600086600001516001600160a01b03166001600160a01b031681526020019081526020016000205461091a565b9052611629565b610100840181905260a084019290925260e0830151909350146104955761010081015160038a0181905560e08201516040517fceb182d5d0a740eee7db26b536f6262ac3c83f61518a662039ec236f98c09d7492610452928252602082015260400190565b60405180910390a160008161010001518260e001516104719190614478565b1361047d576000610492565b8061010001518160e001516104929190614478565b92505b805161012082015160028c015460048d01546104c19392869290916001600160a01b0390911690611a31565b6080830152606082015261012081015160a082015160c08301516104eb928a929091899190611b60565b60a08301819052606083015160808401516040519398507f4c300a656bfa0935e36cd55e92634bc20b2b7e0a0ebf424a2a25bfaac3a01e7693610533938a93909290916144d8565b60405180910390a15097509795505050505050565b60008061055b8a8a8a8a8a8a8a8a611d68565b915091505b9850989650505050505050565b60008061057c86868686611e72565b9150915094509492505050565b6040805160a0810182526001600160a01b03808716825285166020820152908101879052606081018690528651608082018190526000919082906105d09085908b90610b95565b90506105dd828287610c2b565b9998505050505050505050565b6000806105fb888888888888611fa6565b915091505b965096945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561064b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066f9190614511565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190614511565b92915050565b8451606090806001600160401b038111156106f3576106f3613e6b565b60405190808252806020026020018201604052801561071c578160200160208202803683370190505b50915060008061072d858a8561242f565b9150915060005b8381101561090c576000888a83815181106107515761075161444c565b60200260200101518d610764919061452e565b61076e9190614545565b905087820361079b578086838151811061078a5761078a61444c565b602002602001018181525050610903565b60008389815181106107af576107af61444c565b60200260200101518584815181106107c9576107c961444c565b60200260200101518585815181106107e3576107e361444c565b6020026020010151878c815181106107fd576107fd61444c565b602002602001015185610810919061452e565b61081a919061452e565b6108249190614545565b61082e9190614545565b905060008c84815181106108445761084461444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016108779190614567565b602060405180830381865afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b8919061457b565b90508181101561090057816108cd8282614594565b6108d7908561452e565b6108e19190614545565b8885815181106108f3576108f361444c565b6020026020010181815250505b50505b50600101610734565b505050509695505050505050565b6000811561092857816106d0565b620186a092915050565b8351606090806001600160401b0381111561094f5761094f613e6b565b604051908082528060200260200182016040528015610978578160200160208202803683370190505b509150600086868151811061098f5761098f61444c565b6020026020010151905060005b82811015610adc57868114610ad45760008882815181106109bf576109bf61444c565b602002602001015190508682815181106109db576109db61444c565b6020026020010151600014610a4757610a0e83888481518110610a0057610a0061444c565b60200260200101518c61261d565b610a448a6040518060200160405280600081525085848b8781518110610a3657610a3661444c565b60200260200101518b611fa6565b50505b6040516370a0823160e01b81526001600160a01b038216906370a0823190610a73903090600401614567565b602060405180830381865afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab4919061457b565b858381518110610ac657610ac661444c565b602002602001018181525050505b60010161099c565b50610b6c858781518110610af257610af261444c565b6020026020010151826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b269190614567565b602060405180830381865afa158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b67919061457b565b612713565b838781518110610b7e57610b7e61444c565b602002602001018181525050505095945050505050565b6060816001600160401b03811115610baf57610baf613e6b565b604051908082528060200260200182016040528015610bd8578160200160208202803683370190505b50905060005b82811015610c2357610bfe8560008684815181106101ce576101ce61444c565b828281518110610c1057610c1061444c565b6020908102919091010152600101610bde565b509392505050565b600081156115e257610c3c82612729565b9150610cbd604051806101c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001600081526020016000151581526020016000151581525090565b8460400151856060015181518110610cd757610cd761444c565b60209081029190910101516001600160a01b0316815260808501516001600160401b03811115610d0957610d09613e6b565b604051908082528060200260200182016040528015610d32578160200160208202803683370190505b5061014082015280516040516370a0823160e01b81526001600160a01b03909116906370a0823190610d68903090600401614567565b602060405180830381865afa158015610d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da9919061457b565b9150610dca610dbb866000015161060b565b8660400151876080015161242f565b61012083015261010082015260005b85608001518110156115df57606086015181146115d75781516040516370a0823160e01b81526001600160a01b03909116906370a0823190610e1f903090600401614567565b602060405180830381865afa158015610e3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e60919061457b565b60208301526040860151805182908110610e7c57610e7c61444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610eaf9190614567565b602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef0919061457b565b60408301525b730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b03168152508860400151888661010001518761012001518861014001516040518060e001604052806000815260200160008152602001600081526020018d81526020018f6060015181526020018a815260200160008152506040518863ffffffff1660e01b8152600401610fc697969594939291906145ca565b606060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614670565b60e085015260c084015260a08301819052158015611027575060e0820151155b6115a35760008260a0015160001461127757600060018460a0015161104c9190614594565b9050600088606001518214611065578860600151611067565b835b90506110db89600001518a602001518b60400151858151811061108c5761108c61444c565b60200260200101518c6040015185815181106110aa576110aa61444c565b60200260200101518960c0015161012c8e89815181106110cc576110cc61444c565b60200260200101516000611d68565b5060608a015190935082036110fb576110f48684612761565b9550611274565b8860600151810361127457846101200151848151811061111d5761111d61444c565b60200260200101518561010001518a60600151815181106111405761114061444c565b60200260200101518661012001518b60600151815181106111635761116361444c565b602002602001015187610100015187815181106111825761118261444c565b602002602001015186611195919061452e565b61119f919061452e565b6111a99190614545565b6111b39190614545565b6111bd908761469e565b9550600085600001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016111f19190614567565b602060405180830381865afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611232919061457b565b905087898b606001518151811061124b5761124b61444c565b60200260200101518261125e919061469e565b1115611272576020860152506115a3915050565b505b50505b60e08301511561145c57600060018460e001516112949190614594565b90506000886060015182146112ad5788606001516112af565b835b90506000896040015183815181106112c9576112c961444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112fc9190614567565b602060405180830381865afa158015611319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133d919061457b565b9050600080600061138e8d600001518e6040015187815181106113625761136261444c565b60200260200101518f6040015189815181106113805761138061444c565b60200260200101518761277b565b9250925092508c6060015186036113be57808a116113ad5760006113b7565b6113b7818b614594565b9950611455565b8c6060015185036114555760408051808201909152601681527554532d32302062616c616e636520646563726561736560501b6020820152878410156114205760405162461bcd60e51b81526004016114179190614701565b60405180910390fd5b50808210156114485780611434838561452e565b61143e9190614545565b6113b7908b61469e565b611452838b61469e565b99505b5050505050505b82516040516370a0823160e01b81526001600160a01b03909116906370a082319061148b903090600401614567565b602060405180830381865afa1580156114a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cc919061457b565b606084015260408701518051839081106114e8576114e861444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161151b9190614567565b602060405180830381865afa158015611538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155c919061457b565b60808401526060830151602084015114801561157f575082608001518360400151145b1580156101a085015260608401516020850152608084015160408501529050610ef6575b83858760600151815181106115ba576115ba61444c565b602002602001015183602001516115d1919061469e565b116115df575b600101610dd9565b50505b9392505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b60606000806116776040518060e001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b60e08501515160a082018190526101008601515160408051808201909152601281527154532d342077726f6e67206c656e6774687360701b602082015291146116d35760405162461bcd60e51b81526004016114179190614701565b508060a001516001600160401b038111156116f0576116f0613e6b565b604051908082528060200260200182016040528015611719578160200160208202803683370190505b50935060005b8160a00151811015611a225785610160015186610140015113156117b95761174d868288610140015161294c565b87610100015183815181106117645761176461444c565b6101408a0192909252602091820201015260c086015180518290811061178c5761178c61444c565b602002602001015186610100015182815181106117ab576117ab61444c565b602002602001015110611a1a575b620186a0866101200151620186a06117d19190614594565b87610100015183815181106117e8576117e861444c565b60200260200101516117fa919061452e565b6118049190614545565b606083018190526080870151620186a09161181f919061452e565b6118299190614545565b6020830152606082015161010087015180518390811061184b5761184b61444c565b602002602001015161185d9190614594565b604083015260e08601518051829081106118795761187961444c565b6020908102919091018101516001600160a01b031660808401526040830151908301516118a6919061469e565b808352156119e7576000196118c38760a001518460800151612d1c565b146119465785606001516001600160a01b031682608001516001600160a01b0316036118ff5760408201516118f8908561469e565b93506119e7565b611934866000015187602001518460800151896060015186604001516113888c60c0015188815181106110cc576110cc61444c565b60c084018190526118f891508561469e565b61198a866000015187602001518460800151896060015186600001516113888c60c00151888151811061197b5761197b61444c565b60200260200101516001611d68565b60c084015250815160608301516101008801518051849081106119af576119af61444c565b60200260200101516119c19190614594565b8360c001516119d0919061452e565b6119da9190614545565b6119e4908561469e565b93505b816020015182606001516119fb9190614594565b858281518110611a0d57611a0d61444c565b6020026020010181815250505b60010161171f565b50505061014092909201519092565b6000806000856001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a989190614511565b6001600160a01b03166389cf32046040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af99190614511565b9050620186a0611b09858961452e565b611b139190614545565b9250611b1f8388614594565b91508215611b3b57611b3b6001600160a01b0389168685612d7a565b8115611b5557611b556001600160a01b0389168284612d7a565b509550959350505050565b6060806000855190506000886001600160a01b031663f645d4f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd9190614511565b905060005b82811015611c7e57868181518110611bec57611bec61444c565b6020026020010151868281518110611c0657611c0661444c565b60200260200101511115611c39576000878281518110611c2857611c2861444c565b602002602001018181525050611c76565b611c76888281518110611c4e57611c4e61444c565b6020026020010151888381518110611c6857611c6861444c565b60200260200101518461261d565b600101611bd2565b50611c898787612dcc565b8151919550935015611d5c57806001600160a01b0316637e0ddbef85858b6001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190614511565b60016040518563ffffffff1660e01b8152600401611d299493929190614714565b600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b505050505b50509550959350505050565b600080838611611d7d57506000905080610560565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611df791908101906147a0565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f7574650000000000006020820152919250611e4e5760405162461bcd60e51b81526004016114179190614701565b5086611e608c838d8d8d8d8d8c612fba565b92509250509850989650505050505050565b6000806000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611ea39190614567565b602060405180830381865afa158015611ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee4919061457b565b60405163dd27ede760e01b81523060048201526001600160a01b03888116602483015287811660448301526001606483015291925060009189169063dd27ede79060840160408051808303816000875af1158015611f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6a91906148b9565b5090506000611f87828710611f7f5782611f81565b865b84612713565b9050611f9689898984876132aa565b9450945050505094509492505050565b60008082600003611fb657600a92505b828411611fc857506000905080610600565b6120016040518060c001604052806000815260200160608152602001606081526020016060815260200160008152602001600081525090565b61200a88613494565b8082526000190161202d576120238989898989896134bb565b9250925050610600565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790612064908b908b908a908c906213c680906004016148dd565b600060405180830381865afa158015612081573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120a99190810190614979565b5060608401526040830152602082018190525180156124285760005b818110156124265782516121d557826040015181815181106120e9576120e961444c565b6020026020010151871061211a578260400151818151811061210d5761210d61444c565b602002602001015161211c565b865b608084015260408301518051829081106121385761213861444c565b60200260200101518710612169578260600151818151811061215c5761215c61444c565b60200260200101516121ba565b8260400151818151811061217f5761217f61444c565b6020026020010151878460600151838151811061219e5761219e61444c565b60200260200101516121b0919061452e565b6121ba9190614545565b60a084015260808301516121ce9088614594565b96506122d3565b826060015181815181106121eb576121eb61444c565b6020026020010151871061221c578260600151818151811061220f5761220f61444c565b602002602001015161221e565b865b60a0840152606083015180518290811061223a5761223a61444c565b6020026020010151871061226b578260400151818151811061225e5761225e61444c565b60200260200101516122bc565b826060015181815181106122815761228161444c565b602002602001015187846040015183815181106122a0576122a061444c565b60200260200101516122b2919061452e565b6122bc9190614545565b608084015260a08301516122d09088614594565b96505b85871080156122e157508615155b156122eb57600096505b60a083015115612418578a6001600160a01b0316630adb2d858460200151838151811061231a5761231a61444c565b60200260200101518b86608001518c8860a00151306040518763ffffffff1660e01b815260040161235096959493929190614a86565b6020604051808303816000875af115801561236f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612393919061457b565b61239d908561469e565b93508260800151856123af919061469e565b94507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec836020015182815181106123e8576123e861444c565b60200260200101518a85608001518b8760a001513060405161240f96959493929190614a86565b60405180910390a15b8615612426576001016120c5565b505b5050610600565b606080826001600160401b0381111561244a5761244a613e6b565b604051908082528060200260200182016040528015612473578160200160208202803683370190505b509150826001600160401b0381111561248e5761248e613e6b565b6040519080825280602002602001820160405280156124b7578160200160208202803683370190505b50905060005b83811015612614578481815181106124d7576124d761444c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561251c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125409190614abe565b61254b90600a614bc5565b82828151811061255d5761255d61444c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061258a5761258a61444c565b60200260200101516040518263ffffffff1660e01b81526004016125ae9190614567565b602060405180830381865afa1580156125cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ef919061457b565b8382815181106126015761260161444c565b60209081029190910101526001016124bd565b50935093915050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561266c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612690919061457b565b101561270e5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156126e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270c9190614bd4565b505b505050565b600081831061272257816115e2565b5090919050565b6000600019821461275d57620186a06127446113888261469e565b61274e908461452e565b6127589190614545565b6106d0565b5090565b60008183116127715760006115e2565b6115e28284614594565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016127ad9190614567565b602060405180830381865afa1580156127ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ee919061457b565b60405163dd27ede760e01b81523060048201526001600160a01b0389811660248301528881166044830152600160648301529192506000918a169063dd27ede79060840160408051808303816000875af1158015612850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287491906148b9565b50905061288f8187106128875781612889565b865b83612713565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af11580156128f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291591906148b9565b90965090508086111561292f5761292c8187614594565b95505b61293c8a8a8a87876132aa565b9550505050509450945094915050565b6000806000808660e0015186815181106129685761296861444c565b60200260200101516001600160a01b031687606001516001600160a01b0316036129be576129b48588610100015188815181106129a7576129a761444c565b6020026020010151612713565b9150819050612b8b565b600087610160015188610100015188815181106129dd576129dd61444c565b6020026020010151116129f1576000612abf565b87602001516001600160a01b031663a9dd14d68960e001518981518110612a1a57612a1a61444c565b60200260200101518a606001518b61010001518b81518110612a3e57612a3e61444c565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015612a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abf919061457b565b9050600088610160015187612ad4919061469e565b821115612b175781878a61010001518a81518110612af457612af461444c565b6020026020010151612b06919061452e565b612b109190614545565b9050612b39565b8861010001518881518110612b2e57612b2e61444c565b602002602001015190505b612b8389600001518a602001518b60e001518b81518110612b5c57612b5c61444c565b60200260200101518c60600151856113888f60c001518f8151811061197b5761197b61444c565b909450925050505b612c6a87604001516001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf49190614511565b6001600160a01b03166389cf32046040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190614511565b60608901516001600160a01b03169083612d7a565b612c928761010001518781518110612c8457612c8461444c565b602002602001015183612761565b9350612c9e8186614478565b92507f25f353a73b632dcffa5ff4f0edc2f19635d557167df35e97b06545b3f4bd3e8b8760e001518781518110612cd757612cd761444c565b602090810291909101810151604080516001600160a01b0390921682529181018590529081018790526060810185905260800160405180910390a15050935093915050565b8151600090815b81811015612d6e57836001600160a01b0316858281518110612d4757612d4761444c565b60200260200101516001600160a01b031603612d665791506106d09050565b600101612d23565b50600019949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261270e9084906139fb565b60608082518451146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090612e185760405162461bcd60e51b81526004016114179190614701565b508351600090815b81811015612e6957858181518110612e3a57612e3a61444c565b6020026020010151600014612e575782612e5381614bf1565b9350505b80612e6181614bf1565b915050612e20565b50816001600160401b03811115612e8257612e82613e6b565b604051908082528060200260200182016040528015612eab578160200160208202803683370190505b509350816001600160401b03811115612ec657612ec6613e6b565b604051908082528060200260200182016040528015612eef578160200160208202803683370190505b5092506000805b82811015612faf576000878281518110612f1257612f1261444c565b6020026020010151905080600014612f9c57888281518110612f3657612f3661444c565b6020026020010151878481518110612f5057612f5061444c565b60200260200101906001600160a01b031690816001600160a01b03168152505080868481518110612f8357612f8361444c565b602090810291909101015282612f9881614bf1565b9350505b5080612fa781614bf1565b915050612ef6565b505050509250929050565b6000612fc786858961261d565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612ff6903090600401614567565b602060405180830381865afa158015613013573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613037919061457b565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c89061306a908c9089908990600401614c0a565b600060405180830381600087803b15801561308457600080fd5b505af1158015613098573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a08231906130cb903090600401614567565b602060405180830381865afa1580156130e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310c919061457b565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b8152509061315e5760405162461bcd60e51b81526004016114179190614701565b506131698282614594565b925083806131f95750604051630a47e27160e21b81526001600160a01b03898116600483015260248201889052888116604483015260648201859052608482018790528c169063291f89c49060a401602060405180830381865afa1580156131d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f99190614bd4565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906132425760405162461bcd60e51b81526004016114179190614701565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b6000806064841061348a576132c96001600160a01b0386168886612d7a565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561332a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334e9190614c8c565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906133e3903090600401614567565b602060405180830381865afa158015613400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613424919061457b565b905080851161343457600061343e565b61343e8186614594565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156134865760405162461bcd60e51b81526004016114179190614701565b5050505b9550959350505050565b600081516000036134a757506000919050565b818060200190518101906106d0919061457b565b60008061350660405180610100016040528060608152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb179061353d908b908b908a908c906213c680906004016148dd565b600060405180830381865afa15801561355a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135829190810190614979565b50604084015260208301528082525180156139ee576000808a8060200190518101906135ae9190614670565b92509250506135be8c8b8b613acd565b60e085015260005b838110156139ea57670de0b6b3a7640000856040015182815181106135ed576135ed61444c565b60200260200101518660e00151613604919061452e565b61360e9190614545565b60c086018190528290613621908561452e565b61362b9190614545565b60a08601819052602086015180518b9291908490811061364d5761364d61444c565b602002602001015161365f919061469e565b1115613735578460a00151856020015182815181106136805761368061444c565b6020026020010151613692919061469e565b89866020015183815181106136a9576136a961444c565b60200260200101516136bb919061452e565b6136c59190614545565b606086015260a085015160208601518051839081106136e6576136e661444c565b60200260200101516136f8919061469e565b898660400151838151811061370f5761370f61444c565b6020026020010151613721919061452e565b61372b9190614545565b6080860152613784565b8460200151818151811061374b5761374b61444c565b6020026020010151856060018181525050846040015181815181106137725761377261444c565b60200260200101518560800181815250505b878560600151108061379857506080850151155b156137e05788888660a00151876020015184815181106137ba576137ba61444c565b60200260200101516137cc919061469e565b6137d6919061469e565b116139ea576139e2565b84608001518d6001600160a01b0316630adb2d858760000151848151811061380a5761380a61444c565b60200260200101518e89606001518f8b60800151306040518763ffffffff1660e01b815260040161384096959493929190614a86565b6020604051808303816000875af115801561385f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613883919061457b565b146040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906138ca5760405162461bcd60e51b81526004016114179190614701565b507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec856000015182815181106139025761390261444c565b60200260200101518c87606001518d89608001513060405161392996959493929190614a86565b60405180910390a16080850151613940908761469e565b9550846060015187613952919061469e565b9650670de0b6b3a764000085608001518660e00151613971919061452e565b61397b9190614545565b60c08601819052829061398e908561452e565b6139989190614545565b60a0860181905260608601516139ad9161469e565b89116139ba5760006139d8565b84606001518560a001516139ce919061469e565b6139d8908a614594565b98508789106139ea575b6001016135c6565b5050505b5050965096945050505050565b6000613a50826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613cd39092919063ffffffff16565b80519091501561270e5780806020019051810190613a6e9190614bd4565b61270e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611417565b600080613ad98561060b565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613b099190614567565b602060405180830381865afa158015613b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b4a919061457b565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613b7a9190614567565b602060405180830381865afa158015613b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bbb919061457b565b9050846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1f9190614abe565b613c2a90600a614bc5565b82876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8d9190614abe565b613c9890600a614bc5565b613caa84670de0b6b3a764000061452e565b613cb4919061452e565b613cbe9190614545565b613cc89190614545565b979650505050505050565b6060613ce28484600085613cea565b949350505050565b606082471015613d4b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611417565b600080866001600160a01b03168587604051613d679190614cc2565b60006040518083038185875af1925050503d8060008114613da4576040519150601f19603f3d011682016040523d82523d6000602084013e613da9565b606091505b5091509150613cc88783838760608315613e24578251600003613e1d576001600160a01b0385163b613e1d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611417565b5081613ce2565b613ce28383815115613e395781518083602001fd5b8060405162461bcd60e51b81526004016114179190614701565b6001600160a01b0381168114613e6857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613ea357613ea3613e6b565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613ed157613ed1613e6b565b604052919050565b60006001600160401b03821115613ef257613ef2613e6b565b5060051b60200190565b8035613f0781613e53565b919050565b600082601f830112613f1d57600080fd5b81356020613f32613f2d83613ed9565b613ea9565b82815260059290921b84018101918181019086841115613f5157600080fd5b8286015b84811015613f75578035613f6881613e53565b8352918301918301613f55565b509695505050505050565b600082601f830112613f9157600080fd5b81356020613fa1613f2d83613ed9565b82815260059290921b84018101918181019086841115613fc057600080fd5b8286015b84811015613f755780358352918301918301613fc4565b600080600080600080600060e0888a031215613ff657600080fd5b873561400181613e53565b96506020880135955060408801356001600160401b038082111561402457600080fd5b6140308b838c01613f0c565b965060608a0135955060808a013591508082111561404d57600080fd5b5061405a8a828b01613f80565b93505060a0880135915060c0880135905092959891949750929550565b600081518084526020808501945080840160005b838110156140a75781518752958201959082019060010161408b565b509495945050505050565b6020815260006115e26020830184614077565b60008060008060008060c087890312156140de57600080fd5b86356140e981613e53565b955060208701356140f981613e53565b945060408701359350606087013592506080870135915060a08701356001600160401b0381111561412957600080fd5b61413589828a01613f0c565b9150509295509295509295565b600080600080600080600060e0888a03121561415d57600080fd5b873596506020880135955060408801356001600160401b038082111561418257600080fd5b61418e8b838c01613f0c565b965060608a013591506141a082613e53565b9094506080890135935060a089013590808211156141bd57600080fd5b6141c98b838c01613f0c565b935060c08a01359150808211156141df57600080fd5b506141ec8a828b01613f80565b91505092959891949750929550565b8015158114613e6857600080fd5b600080600080600080600080610100898b03121561422657600080fd5b883561423181613e53565b9750602089013561424181613e53565b9650604089013561425181613e53565b9550606089013561426181613e53565b94506080890135935060a0890135925060c0890135915060e0890135614286816141fb565b809150509295985092959890939650565b600080600080608085870312156142ad57600080fd5b84356142b881613e53565b935060208501356142c881613e53565b925060408501356142d881613e53565b9396929550929360600135925050565b60008060008060008060c0878903121561430157600080fd5b86356001600160401b0381111561431757600080fd5b61432389828a01613f0c565b96505060208701359450604087013561433b81613e53565b9350606087013561434b81613e53565b9598949750929560808101359460a0909101359350915050565b60006001600160401b0382111561437e5761437e613e6b565b50601f01601f191660200190565b60008060008060008060c087890312156143a557600080fd5b86356143b081613e53565b955060208701356001600160401b038111156143cb57600080fd5b8701601f810189136143dc57600080fd5b80356143ea613f2d82614365565b8181528a60208385010111156143ff57600080fd5b8160208401602083013760006020838301015280975050505061442460408801613efc565b935061443260608801613efc565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103600083128015838313168383128216171561449857614498614462565b5092915050565b600081518084526020808501945080840160005b838110156140a75781516001600160a01b0316875295820195908201906001016144b3565b6080815260006144eb608083018761449f565b82810360208401526144fd8187614077565b604084019590955250506060015292915050565b60006020828403121561452357600080fd5b81516115e281613e53565b80820281158282048414176106d0576106d0614462565b60008261456257634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0391909116815260200190565b60006020828403121561458d57600080fd5b5051919050565b818103818111156106d0576106d0614462565b8060005b600781101561270c5781518452602093840193909101906001016145ab565b60006101c0828a835b60028110156145fb5781516001600160a01b03168352602092830192909101906001016145d3565b5050508060408401526146108184018a61449f565b905082810360608401526146248189614077565b905082810360808401526146388188614077565b905082810360a084015261464c8187614077565b905082810360c08401526146608186614077565b91505061020160e08301846145a7565b60008060006060848603121561468557600080fd5b8351925060208401519150604084015190509250925092565b808201808211156106d0576106d0614462565b60005b838110156146cc5781810151838201526020016146b4565b50506000910152565b600081518084526146ed8160208601602086016146b1565b601f01601f19169290920160200192915050565b6020815260006115e260208301846146d5565b608081526000614727608083018761449f565b82810360208401526147398187614077565b6001600160a01b03959095166040840152505090151560609091015292915050565b600082601f83011261476c57600080fd5b815161477a613f2d82614365565b81815284602083860101111561478f57600080fd5b613ce28260208301602087016146b1565b60008060408084860312156147b457600080fd5b83516001600160401b03808211156147cb57600080fd5b818601915086601f8301126147df57600080fd5b815160206147ef613f2d83613ed9565b82815260079290921b8401810191818101908a84111561480e57600080fd5b948201945b83861015614888576080868c03121561482c5760008081fd5b614834613e81565b865161483f81613e53565b81528684015161484e81613e53565b818501528688015161485f81613e53565b8189015260608781015161487281613e53565b9082015282526080959095019490820190614813565b918901519197509094505050808311156148a157600080fd5b50506148af8582860161475b565b9150509250929050565b600080604083850312156148cc57600080fd5b505080516020909101519092909150565b60a0815260006148f060a08301886146d5565b6001600160a01b03968716602084015260408301959095525091909316606082015260800191909152919050565b600082601f83011261492f57600080fd5b8151602061493f613f2d83613ed9565b82815260059290921b8401810191818101908684111561495e57600080fd5b8286015b84811015613f755780518352918301918301614962565b6000806000806080858703121561498f57600080fd5b84516001600160401b03808211156149a657600080fd5b818701915087601f8301126149ba57600080fd5b815160206149ca613f2d83613ed9565b82815260059290921b8401810191818101908b8411156149e957600080fd5b948201945b83861015614a10578551614a0181613e53565b825294820194908201906149ee565b918a0151919850909350505080821115614a2957600080fd5b614a358883890161491e565b94506040870151915080821115614a4b57600080fd5b614a578883890161491e565b93506060870151915080821115614a6d57600080fd5b50614a7a8782880161491e565b91505092959194509250565b6001600160a01b039687168152948616602086015260408501939093529084166060840152608083015290911660a082015260c00190565b600060208284031215614ad057600080fd5b815160ff811681146115e257600080fd5b600181815b80851115614b1c578160001904821115614b0257614b02614462565b80851615614b0f57918102915b93841c9390800290614ae6565b509250929050565b600082614b33575060016106d0565b81614b40575060006106d0565b8160018114614b565760028114614b6057614b7c565b60019150506106d0565b60ff841115614b7157614b71614462565b50506001821b6106d0565b5060208310610133831016604e8410600b8410161715614b9f575081810a6106d0565b614ba98383614ae1565b8060001904821115614bbd57614bbd614462565b029392505050565b60006115e260ff841683614b24565b600060208284031215614be657600080fd5b81516115e2816141fb565b600060018201614c0357614c03614462565b5060010190565b6060808252845182820181905260009190608090818501906020808a01865b83811015614c7157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614c29565b50508601979097526040909401949094525090949350505050565b60008060008060808587031215614ca257600080fd5b505082516020840151604085015160609095015191969095509092509050565b60008251614cd48184602087016146b1565b919091019291505056fea26469706673582212201338e9ce4b57e92f4f60b7e669911be62def143580d6308a5694265c5768eea064736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c80633542989d1461007c57806358b54f16146100b25780635dcb6130146100e05780637de8f56914610115578063954d7e7314610135578063c432aee114610155578063ca27d10d14610175575b600080fd5b81801561008857600080fd5b5061009c610097366004613fdb565b610195565b6040516100a991906140b2565b60405180910390f35b8180156100be57600080fd5b506100d26100cd3660046140c5565b61020d565b6040519081526020016100a9565b8180156100ec57600080fd5b506101006100fb366004614142565b610261565b604080519283526020830191909152016100a9565b81801561012157600080fd5b50610100610130366004614209565b610548565b81801561014157600080fd5b50610100610150366004614297565b61056d565b81801561016157600080fd5b506100d26101703660046142e8565b610589565b81801561018157600080fd5b5061010061019036600461438c565b6105ea565b60606101ad87878686896101a88e61060b565b6106d6565b9050610201888787846101fc8760008d8d815181106101ce576101ce61444c565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205461091a565b610932565b98975050505050505050565b600080825190506102016040518060a001604052808a6001600160a01b03168152602001896001600160a01b031681526020018581526020018881526020018381525061025b878685610b95565b86610c2b565b6000806102cc60405180610140016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016060815260200160608152602001600081526020016000815260200160006001600160a01b031681525090565b89546001600160a01b0316815260058a0154602082015260038a0154604082015284516102fc9087908790610b95565b60c0820152600389015460e08201526001808b01546001600160a01b03908116610120840152604080516101808101909152918b01541681526103ed90602081016103468a6115e9565b6001600160a01b031681526020018361012001516001600160a01b0316815260200183600001516001600160a01b03168152602001836020015181526020018a81526020018360c001518152602001878152602001868152602001836040015181526020018360e0015181526020016103e689600086600001516001600160a01b03166001600160a01b031681526020019081526020016000205461091a565b9052611629565b610100840181905260a084019290925260e0830151909350146104955761010081015160038a0181905560e08201516040517fceb182d5d0a740eee7db26b536f6262ac3c83f61518a662039ec236f98c09d7492610452928252602082015260400190565b60405180910390a160008161010001518260e001516104719190614478565b1361047d576000610492565b8061010001518160e001516104929190614478565b92505b805161012082015160028c015460048d01546104c19392869290916001600160a01b0390911690611a31565b6080830152606082015261012081015160a082015160c08301516104eb928a929091899190611b60565b60a08301819052606083015160808401516040519398507f4c300a656bfa0935e36cd55e92634bc20b2b7e0a0ebf424a2a25bfaac3a01e7693610533938a93909290916144d8565b60405180910390a15097509795505050505050565b60008061055b8a8a8a8a8a8a8a8a611d68565b915091505b9850989650505050505050565b60008061057c86868686611e72565b9150915094509492505050565b6040805160a0810182526001600160a01b03808716825285166020820152908101879052606081018690528651608082018190526000919082906105d09085908b90610b95565b90506105dd828287610c2b565b9998505050505050505050565b6000806105fb888888888888611fa6565b915091505b965096945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561064b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066f9190614511565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190614511565b92915050565b8451606090806001600160401b038111156106f3576106f3613e6b565b60405190808252806020026020018201604052801561071c578160200160208202803683370190505b50915060008061072d858a8561242f565b9150915060005b8381101561090c576000888a83815181106107515761075161444c565b60200260200101518d610764919061452e565b61076e9190614545565b905087820361079b578086838151811061078a5761078a61444c565b602002602001018181525050610903565b60008389815181106107af576107af61444c565b60200260200101518584815181106107c9576107c961444c565b60200260200101518585815181106107e3576107e361444c565b6020026020010151878c815181106107fd576107fd61444c565b602002602001015185610810919061452e565b61081a919061452e565b6108249190614545565b61082e9190614545565b905060008c84815181106108445761084461444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016108779190614567565b602060405180830381865afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b8919061457b565b90508181101561090057816108cd8282614594565b6108d7908561452e565b6108e19190614545565b8885815181106108f3576108f361444c565b6020026020010181815250505b50505b50600101610734565b505050509695505050505050565b6000811561092857816106d0565b620186a092915050565b8351606090806001600160401b0381111561094f5761094f613e6b565b604051908082528060200260200182016040528015610978578160200160208202803683370190505b509150600086868151811061098f5761098f61444c565b6020026020010151905060005b82811015610adc57868114610ad45760008882815181106109bf576109bf61444c565b602002602001015190508682815181106109db576109db61444c565b6020026020010151600014610a4757610a0e83888481518110610a0057610a0061444c565b60200260200101518c61261d565b610a448a6040518060200160405280600081525085848b8781518110610a3657610a3661444c565b60200260200101518b611fa6565b50505b6040516370a0823160e01b81526001600160a01b038216906370a0823190610a73903090600401614567565b602060405180830381865afa158015610a90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab4919061457b565b858381518110610ac657610ac661444c565b602002602001018181525050505b60010161099c565b50610b6c858781518110610af257610af261444c565b6020026020010151826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b269190614567565b602060405180830381865afa158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b67919061457b565b612713565b838781518110610b7e57610b7e61444c565b602002602001018181525050505095945050505050565b6060816001600160401b03811115610baf57610baf613e6b565b604051908082528060200260200182016040528015610bd8578160200160208202803683370190505b50905060005b82811015610c2357610bfe8560008684815181106101ce576101ce61444c565b828281518110610c1057610c1061444c565b6020908102919091010152600101610bde565b509392505050565b600081156115e257610c3c82612729565b9150610cbd604051806101c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001600081526020016000151581526020016000151581525090565b8460400151856060015181518110610cd757610cd761444c565b60209081029190910101516001600160a01b0316815260808501516001600160401b03811115610d0957610d09613e6b565b604051908082528060200260200182016040528015610d32578160200160208202803683370190505b5061014082015280516040516370a0823160e01b81526001600160a01b03909116906370a0823190610d68903090600401614567565b602060405180830381865afa158015610d85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da9919061457b565b9150610dca610dbb866000015161060b565b8660400151876080015161242f565b61012083015261010082015260005b85608001518110156115df57606086015181146115d75781516040516370a0823160e01b81526001600160a01b03909116906370a0823190610e1f903090600401614567565b602060405180830381865afa158015610e3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e60919061457b565b60208301526040860151805182908110610e7c57610e7c61444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610eaf9190614567565b602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef0919061457b565b60408301525b73__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b03168152508860400151888661010001518761012001518861014001516040518060e001604052806000815260200160008152602001600081526020018d81526020018f6060015181526020018a815260200160008152506040518863ffffffff1660e01b8152600401610fc697969594939291906145ca565b606060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614670565b60e085015260c084015260a08301819052158015611027575060e0820151155b6115a35760008260a0015160001461127757600060018460a0015161104c9190614594565b9050600088606001518214611065578860600151611067565b835b90506110db89600001518a602001518b60400151858151811061108c5761108c61444c565b60200260200101518c6040015185815181106110aa576110aa61444c565b60200260200101518960c0015161012c8e89815181106110cc576110cc61444c565b60200260200101516000611d68565b5060608a015190935082036110fb576110f48684612761565b9550611274565b8860600151810361127457846101200151848151811061111d5761111d61444c565b60200260200101518561010001518a60600151815181106111405761114061444c565b60200260200101518661012001518b60600151815181106111635761116361444c565b602002602001015187610100015187815181106111825761118261444c565b602002602001015186611195919061452e565b61119f919061452e565b6111a99190614545565b6111b39190614545565b6111bd908761469e565b9550600085600001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016111f19190614567565b602060405180830381865afa15801561120e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611232919061457b565b905087898b606001518151811061124b5761124b61444c565b60200260200101518261125e919061469e565b1115611272576020860152506115a3915050565b505b50505b60e08301511561145c57600060018460e001516112949190614594565b90506000886060015182146112ad5788606001516112af565b835b90506000896040015183815181106112c9576112c961444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112fc9190614567565b602060405180830381865afa158015611319573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061133d919061457b565b9050600080600061138e8d600001518e6040015187815181106113625761136261444c565b60200260200101518f6040015189815181106113805761138061444c565b60200260200101518761277b565b9250925092508c6060015186036113be57808a116113ad5760006113b7565b6113b7818b614594565b9950611455565b8c6060015185036114555760408051808201909152601681527554532d32302062616c616e636520646563726561736560501b6020820152878410156114205760405162461bcd60e51b81526004016114179190614701565b60405180910390fd5b50808210156114485780611434838561452e565b61143e9190614545565b6113b7908b61469e565b611452838b61469e565b99505b5050505050505b82516040516370a0823160e01b81526001600160a01b03909116906370a082319061148b903090600401614567565b602060405180830381865afa1580156114a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cc919061457b565b606084015260408701518051839081106114e8576114e861444c565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161151b9190614567565b602060405180830381865afa158015611538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061155c919061457b565b60808401526060830151602084015114801561157f575082608001518360400151145b1580156101a085015260608401516020850152608084015160408501529050610ef6575b83858760600151815181106115ba576115ba61444c565b602002602001015183602001516115d1919061469e565b116115df575b600101610dd9565b50505b9392505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ac573d6000803e3d6000fd5b60606000806116776040518060e001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b60e08501515160a082018190526101008601515160408051808201909152601281527154532d342077726f6e67206c656e6774687360701b602082015291146116d35760405162461bcd60e51b81526004016114179190614701565b508060a001516001600160401b038111156116f0576116f0613e6b565b604051908082528060200260200182016040528015611719578160200160208202803683370190505b50935060005b8160a00151811015611a225785610160015186610140015113156117b95761174d868288610140015161294c565b87610100015183815181106117645761176461444c565b6101408a0192909252602091820201015260c086015180518290811061178c5761178c61444c565b602002602001015186610100015182815181106117ab576117ab61444c565b602002602001015110611a1a575b620186a0866101200151620186a06117d19190614594565b87610100015183815181106117e8576117e861444c565b60200260200101516117fa919061452e565b6118049190614545565b606083018190526080870151620186a09161181f919061452e565b6118299190614545565b6020830152606082015161010087015180518390811061184b5761184b61444c565b602002602001015161185d9190614594565b604083015260e08601518051829081106118795761187961444c565b6020908102919091018101516001600160a01b031660808401526040830151908301516118a6919061469e565b808352156119e7576000196118c38760a001518460800151612d1c565b146119465785606001516001600160a01b031682608001516001600160a01b0316036118ff5760408201516118f8908561469e565b93506119e7565b611934866000015187602001518460800151896060015186604001516113888c60c0015188815181106110cc576110cc61444c565b60c084018190526118f891508561469e565b61198a866000015187602001518460800151896060015186600001516113888c60c00151888151811061197b5761197b61444c565b60200260200101516001611d68565b60c084015250815160608301516101008801518051849081106119af576119af61444c565b60200260200101516119c19190614594565b8360c001516119d0919061452e565b6119da9190614545565b6119e4908561469e565b93505b816020015182606001516119fb9190614594565b858281518110611a0d57611a0d61444c565b6020026020010181815250505b60010161171f565b50505061014092909201519092565b6000806000856001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a989190614511565b6001600160a01b03166389cf32046040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af99190614511565b9050620186a0611b09858961452e565b611b139190614545565b9250611b1f8388614594565b91508215611b3b57611b3b6001600160a01b0389168685612d7a565b8115611b5557611b556001600160a01b0389168284612d7a565b509550959350505050565b6060806000855190506000886001600160a01b031663f645d4f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcd9190614511565b905060005b82811015611c7e57868181518110611bec57611bec61444c565b6020026020010151868281518110611c0657611c0661444c565b60200260200101511115611c39576000878281518110611c2857611c2861444c565b602002602001018181525050611c76565b611c76888281518110611c4e57611c4e61444c565b6020026020010151888381518110611c6857611c6861444c565b60200260200101518461261d565b600101611bd2565b50611c898787612dcc565b8151919550935015611d5c57806001600160a01b0316637e0ddbef85858b6001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190614511565b60016040518563ffffffff1660e01b8152600401611d299493929190614714565b600060405180830381600087803b158015611d4357600080fd5b505af1158015611d57573d6000803e3d6000fd5b505050505b50509550959350505050565b600080838611611d7d57506000905080610560565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611df791908101906147a0565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f7574650000000000006020820152919250611e4e5760405162461bcd60e51b81526004016114179190614701565b5086611e608c838d8d8d8d8d8c612fba565b92509250509850989650505050505050565b6000806000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611ea39190614567565b602060405180830381865afa158015611ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee4919061457b565b60405163dd27ede760e01b81523060048201526001600160a01b03888116602483015287811660448301526001606483015291925060009189169063dd27ede79060840160408051808303816000875af1158015611f46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6a91906148b9565b5090506000611f87828710611f7f5782611f81565b865b84612713565b9050611f9689898984876132aa565b9450945050505094509492505050565b60008082600003611fb657600a92505b828411611fc857506000905080610600565b6120016040518060c001604052806000815260200160608152602001606081526020016060815260200160008152602001600081525090565b61200a88613494565b8082526000190161202d576120238989898989896134bb565b9250925050610600565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790612064908b908b908a908c906213c680906004016148dd565b600060405180830381865afa158015612081573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120a99190810190614979565b5060608401526040830152602082018190525180156124285760005b818110156124265782516121d557826040015181815181106120e9576120e961444c565b6020026020010151871061211a578260400151818151811061210d5761210d61444c565b602002602001015161211c565b865b608084015260408301518051829081106121385761213861444c565b60200260200101518710612169578260600151818151811061215c5761215c61444c565b60200260200101516121ba565b8260400151818151811061217f5761217f61444c565b6020026020010151878460600151838151811061219e5761219e61444c565b60200260200101516121b0919061452e565b6121ba9190614545565b60a084015260808301516121ce9088614594565b96506122d3565b826060015181815181106121eb576121eb61444c565b6020026020010151871061221c578260600151818151811061220f5761220f61444c565b602002602001015161221e565b865b60a0840152606083015180518290811061223a5761223a61444c565b6020026020010151871061226b578260400151818151811061225e5761225e61444c565b60200260200101516122bc565b826060015181815181106122815761228161444c565b602002602001015187846040015183815181106122a0576122a061444c565b60200260200101516122b2919061452e565b6122bc9190614545565b608084015260a08301516122d09088614594565b96505b85871080156122e157508615155b156122eb57600096505b60a083015115612418578a6001600160a01b0316630adb2d858460200151838151811061231a5761231a61444c565b60200260200101518b86608001518c8860a00151306040518763ffffffff1660e01b815260040161235096959493929190614a86565b6020604051808303816000875af115801561236f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612393919061457b565b61239d908561469e565b93508260800151856123af919061469e565b94507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec836020015182815181106123e8576123e861444c565b60200260200101518a85608001518b8760a001513060405161240f96959493929190614a86565b60405180910390a15b8615612426576001016120c5565b505b5050610600565b606080826001600160401b0381111561244a5761244a613e6b565b604051908082528060200260200182016040528015612473578160200160208202803683370190505b509150826001600160401b0381111561248e5761248e613e6b565b6040519080825280602002602001820160405280156124b7578160200160208202803683370190505b50905060005b83811015612614578481815181106124d7576124d761444c565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561251c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125409190614abe565b61254b90600a614bc5565b82828151811061255d5761255d61444c565b602002602001018181525050856001600160a01b031663b3596f0786838151811061258a5761258a61444c565b60200260200101516040518263ffffffff1660e01b81526004016125ae9190614567565b602060405180830381865afa1580156125cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ef919061457b565b8382815181106126015761260161444c565b60209081029190910101526001016124bd565b50935093915050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561266c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612690919061457b565b101561270e5760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af11580156126e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270c9190614bd4565b505b505050565b600081831061272257816115e2565b5090919050565b6000600019821461275d57620186a06127446113888261469e565b61274e908461452e565b6127589190614545565b6106d0565b5090565b60008183116127715760006115e2565b6115e28284614594565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016127ad9190614567565b602060405180830381865afa1580156127ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ee919061457b565b60405163dd27ede760e01b81523060048201526001600160a01b0389811660248301528881166044830152600160648301529192506000918a169063dd27ede79060840160408051808303816000875af1158015612850573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287491906148b9565b50905061288f8187106128875781612889565b865b83612713565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af11580156128f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291591906148b9565b90965090508086111561292f5761292c8187614594565b95505b61293c8a8a8a87876132aa565b9550505050509450945094915050565b6000806000808660e0015186815181106129685761296861444c565b60200260200101516001600160a01b031687606001516001600160a01b0316036129be576129b48588610100015188815181106129a7576129a761444c565b6020026020010151612713565b9150819050612b8b565b600087610160015188610100015188815181106129dd576129dd61444c565b6020026020010151116129f1576000612abf565b87602001516001600160a01b031663a9dd14d68960e001518981518110612a1a57612a1a61444c565b60200260200101518a606001518b61010001518b81518110612a3e57612a3e61444c565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015612a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abf919061457b565b9050600088610160015187612ad4919061469e565b821115612b175781878a61010001518a81518110612af457612af461444c565b6020026020010151612b06919061452e565b612b109190614545565b9050612b39565b8861010001518881518110612b2e57612b2e61444c565b602002602001015190505b612b8389600001518a602001518b60e001518b81518110612b5c57612b5c61444c565b60200260200101518c60600151856113888f60c001518f8151811061197b5761197b61444c565b909450925050505b612c6a87604001516001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf49190614511565b6001600160a01b03166389cf32046040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190614511565b60608901516001600160a01b03169083612d7a565b612c928761010001518781518110612c8457612c8461444c565b602002602001015183612761565b9350612c9e8186614478565b92507f25f353a73b632dcffa5ff4f0edc2f19635d557167df35e97b06545b3f4bd3e8b8760e001518781518110612cd757612cd761444c565b602090810291909101810151604080516001600160a01b0390921682529181018590529081018790526060810185905260800160405180910390a15050935093915050565b8151600090815b81811015612d6e57836001600160a01b0316858281518110612d4757612d4761444c565b60200260200101516001600160a01b031603612d665791506106d09050565b600101612d23565b50600019949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261270e9084906139fb565b60608082518451146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090612e185760405162461bcd60e51b81526004016114179190614701565b508351600090815b81811015612e6957858181518110612e3a57612e3a61444c565b6020026020010151600014612e575782612e5381614bf1565b9350505b80612e6181614bf1565b915050612e20565b50816001600160401b03811115612e8257612e82613e6b565b604051908082528060200260200182016040528015612eab578160200160208202803683370190505b509350816001600160401b03811115612ec657612ec6613e6b565b604051908082528060200260200182016040528015612eef578160200160208202803683370190505b5092506000805b82811015612faf576000878281518110612f1257612f1261444c565b6020026020010151905080600014612f9c57888281518110612f3657612f3661444c565b6020026020010151878481518110612f5057612f5061444c565b60200260200101906001600160a01b031690816001600160a01b03168152505080868481518110612f8357612f8361444c565b602090810291909101015282612f9881614bf1565b9350505b5080612fa781614bf1565b915050612ef6565b505050509250929050565b6000612fc786858961261d565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612ff6903090600401614567565b602060405180830381865afa158015613013573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613037919061457b565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c89061306a908c9089908990600401614c0a565b600060405180830381600087803b15801561308457600080fd5b505af1158015613098573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a08231906130cb903090600401614567565b602060405180830381865afa1580156130e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310c919061457b565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b8152509061315e5760405162461bcd60e51b81526004016114179190614701565b506131698282614594565b925083806131f95750604051630a47e27160e21b81526001600160a01b03898116600483015260248201889052888116604483015260648201859052608482018790528c169063291f89c49060a401602060405180830381865afa1580156131d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f99190614bd4565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906132425760405162461bcd60e51b81526004016114179190614701565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b6000806064841061348a576132c96001600160a01b0386168886612d7a565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561332a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334e9190614c8c565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906133e3903090600401614567565b602060405180830381865afa158015613400573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613424919061457b565b905080851161343457600061343e565b61343e8186614594565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b602082015290935082156134865760405162461bcd60e51b81526004016114179190614701565b5050505b9550959350505050565b600081516000036134a757506000919050565b818060200190518101906106d0919061457b565b60008061350660405180610100016040528060608152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb179061353d908b908b908a908c906213c680906004016148dd565b600060405180830381865afa15801561355a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135829190810190614979565b50604084015260208301528082525180156139ee576000808a8060200190518101906135ae9190614670565b92509250506135be8c8b8b613acd565b60e085015260005b838110156139ea57670de0b6b3a7640000856040015182815181106135ed576135ed61444c565b60200260200101518660e00151613604919061452e565b61360e9190614545565b60c086018190528290613621908561452e565b61362b9190614545565b60a08601819052602086015180518b9291908490811061364d5761364d61444c565b602002602001015161365f919061469e565b1115613735578460a00151856020015182815181106136805761368061444c565b6020026020010151613692919061469e565b89866020015183815181106136a9576136a961444c565b60200260200101516136bb919061452e565b6136c59190614545565b606086015260a085015160208601518051839081106136e6576136e661444c565b60200260200101516136f8919061469e565b898660400151838151811061370f5761370f61444c565b6020026020010151613721919061452e565b61372b9190614545565b6080860152613784565b8460200151818151811061374b5761374b61444c565b6020026020010151856060018181525050846040015181815181106137725761377261444c565b60200260200101518560800181815250505b878560600151108061379857506080850151155b156137e05788888660a00151876020015184815181106137ba576137ba61444c565b60200260200101516137cc919061469e565b6137d6919061469e565b116139ea576139e2565b84608001518d6001600160a01b0316630adb2d858760000151848151811061380a5761380a61444c565b60200260200101518e89606001518f8b60800151306040518763ffffffff1660e01b815260040161384096959493929190614a86565b6020604051808303816000875af115801561385f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613883919061457b565b146040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906138ca5760405162461bcd60e51b81526004016114179190614701565b507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec856000015182815181106139025761390261444c565b60200260200101518c87606001518d89608001513060405161392996959493929190614a86565b60405180910390a16080850151613940908761469e565b9550846060015187613952919061469e565b9650670de0b6b3a764000085608001518660e00151613971919061452e565b61397b9190614545565b60c08601819052829061398e908561452e565b6139989190614545565b60a0860181905260608601516139ad9161469e565b89116139ba5760006139d8565b84606001518560a001516139ce919061469e565b6139d8908a614594565b98508789106139ea575b6001016135c6565b5050505b5050965096945050505050565b6000613a50826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613cd39092919063ffffffff16565b80519091501561270e5780806020019051810190613a6e9190614bd4565b61270e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611417565b600080613ad98561060b565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613b099190614567565b602060405180830381865afa158015613b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b4a919061457b565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613b7a9190614567565b602060405180830381865afa158015613b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bbb919061457b565b9050846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613bfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1f9190614abe565b613c2a90600a614bc5565b82876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8d9190614abe565b613c9890600a614bc5565b613caa84670de0b6b3a764000061452e565b613cb4919061452e565b613cbe9190614545565b613cc89190614545565b979650505050505050565b6060613ce28484600085613cea565b949350505050565b606082471015613d4b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611417565b600080866001600160a01b03168587604051613d679190614cc2565b60006040518083038185875af1925050503d8060008114613da4576040519150601f19603f3d011682016040523d82523d6000602084013e613da9565b606091505b5091509150613cc88783838760608315613e24578251600003613e1d576001600160a01b0385163b613e1d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611417565b5081613ce2565b613ce28383815115613e395781518083602001fd5b8060405162461bcd60e51b81526004016114179190614701565b6001600160a01b0381168114613e6857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613ea357613ea3613e6b565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613ed157613ed1613e6b565b604052919050565b60006001600160401b03821115613ef257613ef2613e6b565b5060051b60200190565b8035613f0781613e53565b919050565b600082601f830112613f1d57600080fd5b81356020613f32613f2d83613ed9565b613ea9565b82815260059290921b84018101918181019086841115613f5157600080fd5b8286015b84811015613f75578035613f6881613e53565b8352918301918301613f55565b509695505050505050565b600082601f830112613f9157600080fd5b81356020613fa1613f2d83613ed9565b82815260059290921b84018101918181019086841115613fc057600080fd5b8286015b84811015613f755780358352918301918301613fc4565b600080600080600080600060e0888a031215613ff657600080fd5b873561400181613e53565b96506020880135955060408801356001600160401b038082111561402457600080fd5b6140308b838c01613f0c565b965060608a0135955060808a013591508082111561404d57600080fd5b5061405a8a828b01613f80565b93505060a0880135915060c0880135905092959891949750929550565b600081518084526020808501945080840160005b838110156140a75781518752958201959082019060010161408b565b509495945050505050565b6020815260006115e26020830184614077565b60008060008060008060c087890312156140de57600080fd5b86356140e981613e53565b955060208701356140f981613e53565b945060408701359350606087013592506080870135915060a08701356001600160401b0381111561412957600080fd5b61413589828a01613f0c565b9150509295509295509295565b600080600080600080600060e0888a03121561415d57600080fd5b873596506020880135955060408801356001600160401b038082111561418257600080fd5b61418e8b838c01613f0c565b965060608a013591506141a082613e53565b9094506080890135935060a089013590808211156141bd57600080fd5b6141c98b838c01613f0c565b935060c08a01359150808211156141df57600080fd5b506141ec8a828b01613f80565b91505092959891949750929550565b8015158114613e6857600080fd5b600080600080600080600080610100898b03121561422657600080fd5b883561423181613e53565b9750602089013561424181613e53565b9650604089013561425181613e53565b9550606089013561426181613e53565b94506080890135935060a0890135925060c0890135915060e0890135614286816141fb565b809150509295985092959890939650565b600080600080608085870312156142ad57600080fd5b84356142b881613e53565b935060208501356142c881613e53565b925060408501356142d881613e53565b9396929550929360600135925050565b60008060008060008060c0878903121561430157600080fd5b86356001600160401b0381111561431757600080fd5b61432389828a01613f0c565b96505060208701359450604087013561433b81613e53565b9350606087013561434b81613e53565b9598949750929560808101359460a0909101359350915050565b60006001600160401b0382111561437e5761437e613e6b565b50601f01601f191660200190565b60008060008060008060c087890312156143a557600080fd5b86356143b081613e53565b955060208701356001600160401b038111156143cb57600080fd5b8701601f810189136143dc57600080fd5b80356143ea613f2d82614365565b8181528a60208385010111156143ff57600080fd5b8160208401602083013760006020838301015280975050505061442460408801613efc565b935061443260608801613efc565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103600083128015838313168383128216171561449857614498614462565b5092915050565b600081518084526020808501945080840160005b838110156140a75781516001600160a01b0316875295820195908201906001016144b3565b6080815260006144eb608083018761449f565b82810360208401526144fd8187614077565b604084019590955250506060015292915050565b60006020828403121561452357600080fd5b81516115e281613e53565b80820281158282048414176106d0576106d0614462565b60008261456257634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0391909116815260200190565b60006020828403121561458d57600080fd5b5051919050565b818103818111156106d0576106d0614462565b8060005b600781101561270c5781518452602093840193909101906001016145ab565b60006101c0828a835b60028110156145fb5781516001600160a01b03168352602092830192909101906001016145d3565b5050508060408401526146108184018a61449f565b905082810360608401526146248189614077565b905082810360808401526146388188614077565b905082810360a084015261464c8187614077565b905082810360c08401526146608186614077565b91505061020160e08301846145a7565b60008060006060848603121561468557600080fd5b8351925060208401519150604084015190509250925092565b808201808211156106d0576106d0614462565b60005b838110156146cc5781810151838201526020016146b4565b50506000910152565b600081518084526146ed8160208601602086016146b1565b601f01601f19169290920160200192915050565b6020815260006115e260208301846146d5565b608081526000614727608083018761449f565b82810360208401526147398187614077565b6001600160a01b03959095166040840152505090151560609091015292915050565b600082601f83011261476c57600080fd5b815161477a613f2d82614365565b81815284602083860101111561478f57600080fd5b613ce28260208301602087016146b1565b60008060408084860312156147b457600080fd5b83516001600160401b03808211156147cb57600080fd5b818601915086601f8301126147df57600080fd5b815160206147ef613f2d83613ed9565b82815260079290921b8401810191818101908a84111561480e57600080fd5b948201945b83861015614888576080868c03121561482c5760008081fd5b614834613e81565b865161483f81613e53565b81528684015161484e81613e53565b818501528688015161485f81613e53565b8189015260608781015161487281613e53565b9082015282526080959095019490820190614813565b918901519197509094505050808311156148a157600080fd5b50506148af8582860161475b565b9150509250929050565b600080604083850312156148cc57600080fd5b505080516020909101519092909150565b60a0815260006148f060a08301886146d5565b6001600160a01b03968716602084015260408301959095525091909316606082015260800191909152919050565b600082601f83011261492f57600080fd5b8151602061493f613f2d83613ed9565b82815260059290921b8401810191818101908684111561495e57600080fd5b8286015b84811015613f755780518352918301918301614962565b6000806000806080858703121561498f57600080fd5b84516001600160401b03808211156149a657600080fd5b818701915087601f8301126149ba57600080fd5b815160206149ca613f2d83613ed9565b82815260059290921b8401810191818101908b8411156149e957600080fd5b948201945b83861015614a10578551614a0181613e53565b825294820194908201906149ee565b918a0151919850909350505080821115614a2957600080fd5b614a358883890161491e565b94506040870151915080821115614a4b57600080fd5b614a578883890161491e565b93506060870151915080821115614a6d57600080fd5b50614a7a8782880161491e565b91505092959194509250565b6001600160a01b039687168152948616602086015260408501939093529084166060840152608083015290911660a082015260c00190565b600060208284031215614ad057600080fd5b815160ff811681146115e257600080fd5b600181815b80851115614b1c578160001904821115614b0257614b02614462565b80851615614b0f57918102915b93841c9390800290614ae6565b509250929050565b600082614b33575060016106d0565b81614b40575060006106d0565b8160018114614b565760028114614b6057614b7c565b60019150506106d0565b60ff841115614b7157614b71614462565b50506001821b6106d0565b5060208310610133831016604e8410600b8410161715614b9f575081810a6106d0565b614ba98383614ae1565b8060001904821115614bbd57614bbd614462565b029392505050565b60006115e260ff841683614b24565b600060208284031215614be657600080fd5b81516115e2816141fb565b600060018201614c0357614c03614462565b5060010190565b6060808252845182820181905260009190608090818501906020808a01865b83811015614c7157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614c29565b50508601979097526040909401949094525090949350505050565b60008060008060808587031215614ca257600080fd5b505082516020840151604085015160609095015191969095509092509050565b60008251614cd48184602087016146b1565b919091019291505056fea26469706673582212201338e9ce4b57e92f4f60b7e669911be62def143580d6308a5694265c5768eea064736f6c63430008110033", + "numDeployments": 28, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrowAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountRepay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recepient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"returnedAssetAmountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"returnedBorrowAmountOut\",\"type\":\"uint256\"}],\"name\":\"ClosePosition\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenIn\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenOut\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"spentAmountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"receivedAmountOut\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"rewardToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"rewardAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"debtToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtLeftovers\",\"type\":\"int256\"}],\"name\":\"OnCoverDebtToInsurance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtToInsuranceBefore\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"debtToInsuraneAfter\",\"type\":\"int256\"}],\"name\":\"OnPayDebtToInsurance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"converter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrowAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recepient\",\"type\":\"address\"}],\"name\":\"OpenPosition\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"rewardTokens\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amountsToForward\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toPerf\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toInsurance\",\"type\":\"uint256\"}],\"name\":\"Recycle\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ReturnAssetToConverter\",\"type\":\"event\"}],\"devdoc\":{\"events\":{\"OnCoverDebtToInsurance(address,uint256,uint256,int256)\":{\"params\":{\"debtLeftovers\":\"Final amount of debt that should be covered, in underlying It can be negative if we paid more than required\",\"debtToCover\":\"Initial amount of debt that should be covered, in underlying\"}},\"OnPayDebtToInsurance(int256,int256)\":{\"params\":{\"debtToInsuranceBefore\":\"Final amount of debts to the insurance, in underlying\"}},\"Recycle(address[],uint256[],uint256,uint256)\":{\"params\":{\"amountsToForward\":\"Amounts to be sent to forwarder\",\"rewardTokens\":\"Full list of reward tokens received from tetuConverter and depositor\"}}},\"kind\":\"dev\",\"methods\":{\"beforeDeposit(ITetuConverter,uint256,address[],uint256,uint256[],uint256,mapping(address => uint256) storage)\":{\"params\":{\"amount_\":\"Amount of underlying to be deposited\",\"indexAsset_\":\"Index of main {asset} in {tokens}\",\"tokens_\":\"Tokens received from {_depositorPoolAssets}\",\"totalWeight_\":\"Sum of {weights_}\",\"weights_\":\"Depositor pool weights\"}},\"closePosition(ITetuConverter,address,address,uint256)\":{\"params\":{\"amountToRepay\":\"Amount to repay in terms of {borrowAsset}\"},\"returns\":{\"repaidAmountOut\":\"Amount that was actually repaid\",\"returnedAssetAmountOut\":\"Amount of collateral received back after repaying\"}},\"closePositionsToGetAmount(ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage,uint256,address[])\":{\"details\":\"We assume here that this function is called before closing any positions in the current block\",\"params\":{\"liquidationThresholds\":\"Min allowed amounts-out for liquidations\",\"requestedBalance\":\"Total amount of the given asset that we need to have on balance at the end. Max uint means attempt to withdraw all possible amount.\"},\"returns\":{\"expectedBalance\":\"Expected asset balance after all swaps and repays\"}},\"liquidate(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,bool)\":{\"params\":{\"liquidationThresholdForTokenIn_\":\"Liquidation threshold for {amountIn_}\",\"skipValidation\":\"Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\"},\"returns\":{\"receivedAmountOut\":\"Amount of {tokenOut_} has been returned by the liquidator\",\"spentAmountIn\":\"Amount of {tokenIn} has been consumed by the liquidator\"}},\"makeRequestedAmount(address[],uint256,ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage)\":{\"params\":{\"indexAsset_\":\"Index of the given {asset} in {tokens}\",\"requestedBalance\":\"Total amount of the given asset that we need to have on balance at the end. Max uint means attempt to withdraw all possible amount.\",\"tokens_\":\"Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\"},\"returns\":{\"expectedBalance\":\"Expected asset balance after all swaps and repays\"}},\"openPosition(ITetuConverter,bytes,address,address,uint256,uint256)\":{\"params\":{\"amountIn_\":\"Meaning depends on {entryData_}.\",\"entryData_\":\"Encoded entry kind and additional params if necessary (set of params depends on the kind) See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\"}},\"recycle(IStrategyV3.BaseState storage,IConverterStrategyBase.ConverterStrategyBaseState storage,address[],address,mapping(address => uint256) storage,address[],uint256[])\":{\"details\":\"{_recycle} is implemented as separate (inline) function to simplify unit testing\",\"params\":{\"rewardAmounts_\":\"Amounts of {rewardTokens_}; we assume, there are no zero amounts here\",\"rewardTokens_\":\"Full list of reward tokens received from tetuConverter and depositor\"},\"returns\":{\"amountPerf\":\"Performance fee in terms of underlying\",\"paidDebtToInsurance\":\"Earned amount spent on debt-to-insurance payment\"}}},\"version\":1},\"userdoc\":{\"events\":{\"ClosePosition(address,address,uint256,address,uint256,uint256)\":{\"notice\":\"Some borrow(s) was/were repaid\"},\"Liquidation(address,address,uint256,uint256,uint256)\":{\"notice\":\"A liquidation was made\"},\"OnCoverDebtToInsurance(address,uint256,uint256,int256)\":{\"notice\":\"Debt to insurance was paid by a reward token\"},\"OnPayDebtToInsurance(int256,int256)\":{\"notice\":\"Debt to insurance was paid by rewards\"},\"OpenPosition(address,address,uint256,address,uint256,address)\":{\"notice\":\"A borrow was made\"},\"Recycle(address[],uint256[],uint256,uint256)\":{\"notice\":\"Recycle was made\"}},\"kind\":\"user\",\"methods\":{\"beforeDeposit(ITetuConverter,uint256,address[],uint256,uint256[],uint256,mapping(address => uint256) storage)\":{\"notice\":\"Default implementation of ConverterStrategyBase.beforeDeposit\"},\"closePosition(ITetuConverter,address,address,uint256)\":{\"notice\":\"Close the given position, pay {amountToRepay}, return collateral amount in result\"},\"closePositionsToGetAmount(ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage,uint256,address[])\":{\"notice\":\"Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\"},\"liquidate(ITetuConverter,ITetuLiquidator,address,address,uint256,uint256,uint256,bool)\":{\"notice\":\"Make liquidation if estimated amountOut exceeds the given threshold\"},\"makeRequestedAmount(address[],uint256,ITetuConverter,ITetuLiquidator,uint256,mapping(address => uint256) storage)\":{\"notice\":\"Convert {amountsToConvert_} to the given {asset} Swap leftovers (if any) to the given asset. If result amount is less than expected, try to close any other available debts (1 repay per block only)\"},\"openPosition(ITetuConverter,bytes,address,address,uint256,uint256)\":{\"notice\":\"Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_} Max possible collateral should be approved before calling of this function.\"},\"recycle(IStrategyV3.BaseState storage,IConverterStrategyBase.ConverterStrategyBaseState storage,address[],address,mapping(address => uint256) storage,address[],uint256[])\":{\"notice\":\"Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder. We have two kinds of rewards: 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets) 2) any other rewards All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound Compound-part of Rewards-2 can be liquidated Compound part of Rewards-1 should be just left on the balance Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance. All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/ConverterStrategyBaseLib.sol\":\"ConverterStrategyBaseLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x614e0a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c80633542989d1461007c57806358b54f16146100b25780635dcb6130146100e05780637de8f56914610115578063954d7e7314610135578063c432aee114610155578063ca27d10d14610175575b600080fd5b81801561008857600080fd5b5061009c6100973660046140d1565b610195565b6040516100a991906141a8565b60405180910390f35b8180156100be57600080fd5b506100d26100cd3660046141bb565b61020d565b6040519081526020016100a9565b8180156100ec57600080fd5b506101006100fb366004614238565b610261565b604080519283526020830191909152016100a9565b81801561012157600080fd5b506101006101303660046142ff565b6106c4565b81801561014157600080fd5b5061010061015036600461438d565b6106e9565b81801561016157600080fd5b506100d26101703660046143de565b610705565b81801561018157600080fd5b50610100610190366004614482565b610766565b60606101ad87878686896101a88e610787565b610852565b9050610201888787846101fc8760008d8d815181106101ce576101ce614542565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054610a96565b610aae565b98975050505050505050565b600080825190506102016040518060a001604052808a6001600160a01b03168152602001896001600160a01b031681526020018581526020018881526020018381525061025b878685610d11565b86610da7565b6000806102e560405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b89546001600160a01b03908116825260018b01541660208083018290526040805163fbfa77cf60e01b8152905163fbfa77cf926004808401939192918290030181865afa15801561033a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035e9190614558565b6001600160a01b031660408083018290528051632273cc8160e21b815290516389cf3204916004808201926020929091908290030181865afa1580156103a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cc9190614558565b81606001906001600160a01b031690816001600160a01b03168152505088600301548160800181815250506104768a600301548b6004015483602001516001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046a9190614575565b84516060860151611755565b61012083015261010082015260408051610180810190915260018a01546001600160a01b03168152600090602081016104ae8a6118af565b6001600160a01b0316815260200183606001516001600160a01b0316815260200183600001516001600160a01b031681526020018a81526020018781526020016104fa89898a51610d11565b81526020018c60050154815260200186815260200183610100015181526020018360800151815260200161055589600086600001516001600160a01b03166001600160a01b0316815260200190815260200160002054610a96565b90529050610562816118ef565b60a085018190526101408501929092526080840151909450146106075760a082015160038b0181905560808301516040517fceb182d5d0a740eee7db26b536f6262ac3c83f61518a662039ec236f98c09d74926105c6928252602082015260400190565b60405180910390a160008260a0015183608001516105e491906145a4565b136105f0576000610604565b8160a00151826080015161060491906145a4565b93505b8151606083015160028d01546101208501516101608501516106399493889390926001600160a01b0390911691611cf7565b8360c0018460e00182815250828152505050610665888360400151888561014001518560c00151611d75565b610140840181905260c084015160e08501516040519399507f4c300a656bfa0935e36cd55e92634bc20b2b7e0a0ebf424a2a25bfaac3a01e76936106ae938b9390929091614604565b60405180910390a1505097509795505050505050565b6000806106d78a8a8a8a8a8a8a8a611f1c565b915091505b9850989650505050505050565b6000806106f886868686612026565b9150915094509492505050565b6040805160a0810182526001600160a01b038087168252851660208201529081018790526060810186905286516080820181905260009190829061074c9085908b90610d11565b9050610759828287610da7565b9998505050505050505050565b60008061077788888888888861215a565b915091505b965096945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107eb9190614558565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084c9190614558565b92915050565b8451606090806001600160401b0381111561086f5761086f613f61565b604051908082528060200260200182016040528015610898578160200160208202803683370190505b5091506000806108a9858a856125e3565b9150915060005b83811015610a88576000888a83815181106108cd576108cd614542565b60200260200101518d6108e0919061463d565b6108ea9190614654565b9050878203610917578086838151811061090657610906614542565b602002602001018181525050610a7f565b600083898151811061092b5761092b614542565b602002602001015185848151811061094557610945614542565b602002602001015185858151811061095f5761095f614542565b6020026020010151878c8151811061097957610979614542565b60200260200101518561098c919061463d565b610996919061463d565b6109a09190614654565b6109aa9190614654565b905060008c84815181106109c0576109c0614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016109f39190614676565b602060405180830381865afa158015610a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a349190614575565b905081811015610a7c5781610a49828261468a565b610a53908561463d565b610a5d9190614654565b888581518110610a6f57610a6f614542565b6020026020010181815250505b50505b506001016108b0565b505050509695505050505050565b60008115610aa4578161084c565b620186a092915050565b8351606090806001600160401b03811115610acb57610acb613f61565b604051908082528060200260200182016040528015610af4578160200160208202803683370190505b5091506000868681518110610b0b57610b0b614542565b6020026020010151905060005b82811015610c5857868114610c50576000888281518110610b3b57610b3b614542565b60200260200101519050868281518110610b5757610b57614542565b6020026020010151600014610bc357610b8a83888481518110610b7c57610b7c614542565b60200260200101518c6127d1565b610bc08a6040518060200160405280600081525085848b8781518110610bb257610bb2614542565b60200260200101518b61215a565b50505b6040516370a0823160e01b81526001600160a01b038216906370a0823190610bef903090600401614676565b602060405180830381865afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c309190614575565b858381518110610c4257610c42614542565b602002602001018181525050505b600101610b18565b50610ce8858781518110610c6e57610c6e614542565b6020026020010151826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610ca29190614676565b602060405180830381865afa158015610cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce39190614575565b6128c7565b838781518110610cfa57610cfa614542565b602002602001018181525050505095945050505050565b6060816001600160401b03811115610d2b57610d2b613f61565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50905060005b82811015610d9f57610d7a8560008684815181106101ce576101ce614542565b828281518110610d8c57610d8c614542565b6020908102919091010152600101610d5a565b509392505050565b6000811561174e57610db8826128dd565b9150610e2960405180610180016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016000151581525090565b8460400151856060015181518110610e4357610e43614542565b60209081029190910101516001600160a01b0316815260808501516001600160401b03811115610e7557610e75613f61565b604051908082528060200260200182016040528015610e9e578160200160208202803683370190505b5061014082015280516040516370a0823160e01b81526001600160a01b03909116906370a0823190610ed4903090600401614676565b602060405180830381865afa158015610ef1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f159190614575565b9150610f36610f278660000151610787565b866040015187608001516125e3565b61012083015261010082015260005b856080015181101561174b57606086015181146117435781516040516370a0823160e01b81526001600160a01b03909116906370a0823190610f8b903090600401614676565b602060405180830381865afa158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190614575565b60208301526040860151805182908110610fe857610fe8614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161101b9190614676565b602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614575565b60408301525b730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b03168152508860400151888661010001518761012001518861014001516040518060e001604052806000815260200160008152602001600081526020018d81526020018f6060015181526020018a815260200160008152506040518863ffffffff1660e01b815260040161113297969594939291906146c0565b606060405180830381865af415801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111739190614766565b60e085015260c084015260a08301819052158015611193575060e0820151155b61170f5760008260a001516000146113e357600060018460a001516111b8919061468a565b90506000886060015182146111d15788606001516111d3565b835b905061124789600001518a602001518b6040015185815181106111f8576111f8614542565b60200260200101518c60400151858151811061121657611216614542565b60200260200101518960c0015161012c8e898151811061123857611238614542565b60200260200101516000611f1c565b5060608a01519093508203611267576112608684612915565b95506113e0565b886060015181036113e057846101200151848151811061128957611289614542565b60200260200101518561010001518a60600151815181106112ac576112ac614542565b60200260200101518661012001518b60600151815181106112cf576112cf614542565b602002602001015187610100015187815181106112ee576112ee614542565b602002602001015186611301919061463d565b61130b919061463d565b6113159190614654565b61131f9190614654565b6113299087614794565b9550600085600001516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161135d9190614676565b602060405180830381865afa15801561137a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139e9190614575565b905087898b60600151815181106113b7576113b7614542565b6020026020010151826113ca9190614794565b11156113de5760208601525061170f915050565b505b50505b60e0830151156115c857600060018460e00151611400919061468a565b905060008860600151821461141957886060015161141b565b835b905060008960400151838151811061143557611435614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114689190614676565b602060405180830381865afa158015611485573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a99190614575565b905060008060006114fa8d600001518e6040015187815181106114ce576114ce614542565b60200260200101518f6040015189815181106114ec576114ec614542565b60200260200101518761292f565b9250925092508c60600151860361152a57808a11611519576000611523565b611523818b61468a565b99506115c1565b8c6060015185036115c15760408051808201909152601681527554532d32302062616c616e636520646563726561736560501b60208201528784101561158c5760405162461bcd60e51b815260040161158391906147f7565b60405180910390fd5b50808210156115b457806115a0838561463d565b6115aa9190614654565b611523908b614794565b6115be838b614794565b99505b5050505050505b82516040516370a0823160e01b81526001600160a01b03909116906370a08231906115f7903090600401614676565b602060405180830381865afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116389190614575565b6060840152604087015180518390811061165457611654614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116879190614676565b602060405180830381865afa1580156116a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c89190614575565b6080840152606083015160208401511480156116eb575082608001518360400151145b15801561016085015260608401516020850152608084015160408501529050611062575b838587606001518151811061172657611726614542565b6020026020010151836020015161173d9190614794565b1161174b575b600101610f45565b50505b9392505050565b60008080620186a0611769610bb88861463d565b6117739190614654565b90506000856001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016117a39190614676565b602060405180830381865afa1580156117c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e49190614575565b90506000620186a06117f68a8c61463d565b6118009190614654565b905060008383101580611811575083155b61185c57620186a0846118248c8361468a565b8d61182f878961468a565b611839919061463d565b611843919061463d565b61184d9190614654565b6118579190614654565b61185f565b60005b905061186b8183614794565b81156118975761187b8284614794565b61188884620186a061463d565b6118929190614654565b61189c565b620186a05b95509550505050505b9550959350505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610828573d6000803e3d6000fd5b606060008061193d6040518060e001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b60a080860151519082018190526101008601515160408051808201909152601281527154532d342077726f6e67206c656e6774687360701b602082015291146119995760405162461bcd60e51b815260040161158391906147f7565b508060a001516001600160401b038111156119b6576119b6613f61565b6040519080825280602002602001820160405280156119df578160200160208202803683370190505b50935060005b8160a00151811015611ce8578561016001518661014001511315611a7f57611a138682886101400151612b00565b8761010001518381518110611a2a57611a2a614542565b6101408a0192909252602091820201015260c0860151805182908110611a5257611a52614542565b60200260200101518661010001518281518110611a7157611a71614542565b602002602001015110611ce0575b620186a0866101200151620186a0611a97919061468a565b8761010001518381518110611aae57611aae614542565b6020026020010151611ac0919061463d565b611aca9190614654565b6060830181905260e0870151620186a091611ae5919061463d565b611aef9190614654565b60208301526060820151610100870151805183908110611b1157611b11614542565b6020026020010151611b23919061468a565b604083015260a0860151805182908110611b3f57611b3f614542565b6020908102919091018101516001600160a01b03166080840152604083015190830151611b6c9190614794565b80835215611cad57600019611b8987608001518460800151612e13565b14611c0c5785606001516001600160a01b031682608001516001600160a01b031603611bc5576040820151611bbe9085614794565b9350611cad565b611bfa866000015187602001518460800151896060015186604001516113888c60c00151888151811061123857611238614542565b60c08401819052611bbe915085614794565b611c50866000015187602001518460800151896060015186600001516113888c60c001518881518110611c4157611c41614542565b60200260200101516001611f1c565b60c08401525081516060830151610100880151805184908110611c7557611c75614542565b6020026020010151611c87919061468a565b8360c00151611c96919061463d565b611ca09190614654565b611caa9085614794565b93505b81602001518260600151611cc1919061468a565b858281518110611cd357611cd3614542565b6020026020010181815250505b6001016119e5565b50505061014092909201519092565b600080620186a0611d08858961463d565b611d129190614654565b9150611d1e828861468a565b90508115611d4b5782821015611d375760009150611d4b565b611d4b6001600160a01b0389168684612e71565b801561077c5782811015611d615750600061077c565b61077c6001600160a01b0389168783612e71565b6060806000855190506000886001600160a01b031663f645d4f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de29190614558565b905060005b82811015611e9357868181518110611e0157611e01614542565b6020026020010151868281518110611e1b57611e1b614542565b60200260200101511115611e4e576000878281518110611e3d57611e3d614542565b602002602001018181525050611e8b565b611e8b888281518110611e6357611e63614542565b6020026020010151888381518110611e7d57611e7d614542565b6020026020010151846127d1565b600101611de7565b50611e9e8787612ec3565b8151919550935015611f1057604051637e0ddbef60e01b81526001600160a01b03821690637e0ddbef90611edd90879087908d9060019060040161480a565b600060405180830381600087803b158015611ef757600080fd5b505af1158015611f0b573d6000803e3d6000fd5b505050505b50509550959350505050565b600080838611611f31575060009050806106dc565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa158015611f83573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611fab9190810190614896565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506120025760405162461bcd60e51b815260040161158391906147f7565b50866120148c838d8d8d8d8d8c6130b1565b92509250509850989650505050505050565b6000806000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120579190614676565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614575565b60405163dd27ede760e01b81523060048201526001600160a01b03888116602483015287811660448301526001606483015291925060009189169063dd27ede79060840160408051808303816000875af11580156120fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211e91906149af565b509050600061213b8287106121335782612135565b865b846128c7565b905061214a89898984876133a1565b9450945050505094509492505050565b6000808260000361216a57600a92505b82841161217c5750600090508061077c565b6121b56040518060c001604052806000815260200160608152602001606081526020016060815260200160008152602001600081525090565b6121be8861358a565b808252600019016121e1576121d78989898989896135b1565b925092505061077c565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790612218908b908b908a908c906213c680906004016149d3565b600060405180830381865afa158015612235573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261225d9190810190614a6f565b5060608401526040830152602082018190525180156125dc5760005b818110156125da578251612389578260400151818151811061229d5761229d614542565b602002602001015187106122ce57826040015181815181106122c1576122c1614542565b60200260200101516122d0565b865b608084015260408301518051829081106122ec576122ec614542565b6020026020010151871061231d578260600151818151811061231057612310614542565b602002602001015161236e565b8260400151818151811061233357612333614542565b6020026020010151878460600151838151811061235257612352614542565b6020026020010151612364919061463d565b61236e9190614654565b60a08401526080830151612382908861468a565b9650612487565b8260600151818151811061239f5761239f614542565b602002602001015187106123d057826060015181815181106123c3576123c3614542565b60200260200101516123d2565b865b60a084015260608301518051829081106123ee576123ee614542565b6020026020010151871061241f578260400151818151811061241257612412614542565b6020026020010151612470565b8260600151818151811061243557612435614542565b6020026020010151878460400151838151811061245457612454614542565b6020026020010151612466919061463d565b6124709190614654565b608084015260a0830151612484908861468a565b96505b858710801561249557508615155b1561249f57600096505b60a0830151156125cc578a6001600160a01b0316630adb2d85846020015183815181106124ce576124ce614542565b60200260200101518b86608001518c8860a00151306040518763ffffffff1660e01b815260040161250496959493929190614b7c565b6020604051808303816000875af1158015612523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125479190614575565b6125519085614794565b93508260800151856125639190614794565b94507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec8360200151828151811061259c5761259c614542565b60200260200101518a85608001518b8760a00151306040516125c396959493929190614b7c565b60405180910390a15b86156125da57600101612279565b505b505061077c565b606080826001600160401b038111156125fe576125fe613f61565b604051908082528060200260200182016040528015612627578160200160208202803683370190505b509150826001600160401b0381111561264257612642613f61565b60405190808252806020026020018201604052801561266b578160200160208202803683370190505b50905060005b838110156127c85784818151811061268b5761268b614542565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f49190614bb4565b6126ff90600a614cbb565b82828151811061271157612711614542565b602002602001018181525050856001600160a01b031663b3596f0786838151811061273e5761273e614542565b60200260200101516040518263ffffffff1660e01b81526004016127629190614676565b602060405180830381865afa15801561277f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a39190614575565b8382815181106127b5576127b5614542565b6020908102919091010152600101612671565b50935093915050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015612820573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128449190614575565b10156128c25760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af115801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c09190614cca565b505b505050565b60008183106128d6578161174e565b5090919050565b6000600019821461291157620186a06128f861138882614794565b612902908461463d565b61290c9190614654565b61084c565b5090565b600081831161292557600061174e565b61174e828461468a565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016129619190614676565b602060405180830381865afa15801561297e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a29190614575565b60405163dd27ede760e01b81523060048201526001600160a01b0389811660248301528881166044830152600160648301529192506000918a169063dd27ede79060840160408051808303816000875af1158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a2891906149af565b509050612a43818710612a3b5781612a3d565b865b836128c7565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015612aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac991906149af565b909650905080861115612ae357612ae0818761468a565b95505b612af08a8a8a87876133a1565b9550505050509450945094915050565b6000806000808660a001518681518110612b1c57612b1c614542565b60200260200101516001600160a01b031687606001516001600160a01b031603612b7257612b68858861010001518881518110612b5b57612b5b614542565b60200260200101516128c7565b9150819050612d3b565b60008761016001518861010001518881518110612b9157612b91614542565b602002602001015111612ba5576000612c73565b87602001516001600160a01b031663a9dd14d68960a001518981518110612bce57612bce614542565b60200260200101518a606001518b61010001518b81518110612bf257612bf2614542565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614575565b9050600088610160015187612c889190614794565b8211612cb2578861010001518881518110612ca557612ca5614542565b6020026020010151612ce7565b81878a61010001518a81518110612ccb57612ccb614542565b6020026020010151612cdd919061463d565b612ce79190614654565b9050612d3389600001518a602001518b60a001518b81518110612d0c57612d0c614542565b60200260200101518c60600151856113888f60c001518f81518110611c4157611c41614542565b909450925050505b612d6187604001518289606001516001600160a01b0316612e719092919063ffffffff16565b612d898761010001518781518110612d7b57612d7b614542565b602002602001015183612915565b9350612d9581866145a4565b92507f25f353a73b632dcffa5ff4f0edc2f19635d557167df35e97b06545b3f4bd3e8b8760a001518781518110612dce57612dce614542565b602090810291909101810151604080516001600160a01b0390921682529181018590529081018790526060810185905260800160405180910390a15050935093915050565b8151600090815b81811015612e6557836001600160a01b0316858281518110612e3e57612e3e614542565b60200260200101516001600160a01b031603612e5d57915061084c9050565b600101612e1a565b50600019949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526128c2908490613af1565b60608082518451146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090612f0f5760405162461bcd60e51b815260040161158391906147f7565b508351600090815b81811015612f6057858181518110612f3157612f31614542565b6020026020010151600014612f4e5782612f4a81614ce7565b9350505b80612f5881614ce7565b915050612f17565b50816001600160401b03811115612f7957612f79613f61565b604051908082528060200260200182016040528015612fa2578160200160208202803683370190505b509350816001600160401b03811115612fbd57612fbd613f61565b604051908082528060200260200182016040528015612fe6578160200160208202803683370190505b5092506000805b828110156130a657600087828151811061300957613009614542565b60200260200101519050806000146130935788828151811061302d5761302d614542565b602002602001015187848151811061304757613047614542565b60200260200101906001600160a01b031690816001600160a01b0316815250508086848151811061307a5761307a614542565b60209081029190910101528261308f81614ce7565b9350505b508061309e81614ce7565b915050612fed565b505050509250929050565b60006130be8685896127d1565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906130ed903090600401614676565b602060405180830381865afa15801561310a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312e9190614575565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890613161908c9089908990600401614d00565b600060405180830381600087803b15801561317b57600080fd5b505af115801561318f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a08231906131c2903090600401614676565b602060405180830381865afa1580156131df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132039190614575565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906132555760405162461bcd60e51b815260040161158391906147f7565b50613260828261468a565b925083806132f05750604051630a47e27160e21b81526001600160a01b03898116600483015260248201889052888116604483015260648201859052608482018790528c169063291f89c49060a401602060405180830381865afa1580156132cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f09190614cca565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906133395760405162461bcd60e51b815260040161158391906147f7565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b600080606484106118a5576133c06001600160a01b0386168886612e71565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015613421573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134459190614d82565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906134da903090600401614676565b602060405180830381865afa1580156134f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351b9190614575565b905080851161352b576000613535565b613535818661468a565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b6020820152909350821561357d5760405162461bcd60e51b815260040161158391906147f7565b5050509550959350505050565b6000815160000361359d57506000919050565b8180602001905181019061084c9190614575565b6000806135fc60405180610100016040528060608152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790613633908b908b908a908c906213c680906004016149d3565b600060405180830381865afa158015613650573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136789190810190614a6f565b5060408401526020830152808252518015613ae4576000808a8060200190518101906136a49190614766565b92509250506136b48c8b8b613bc3565b60e085015260005b83811015613ae057670de0b6b3a7640000856040015182815181106136e3576136e3614542565b60200260200101518660e001516136fa919061463d565b6137049190614654565b60c086018190528290613717908561463d565b6137219190614654565b60a08601819052602086015180518b9291908490811061374357613743614542565b60200260200101516137559190614794565b111561382b578460a001518560200151828151811061377657613776614542565b60200260200101516137889190614794565b898660200151838151811061379f5761379f614542565b60200260200101516137b1919061463d565b6137bb9190614654565b606086015260a085015160208601518051839081106137dc576137dc614542565b60200260200101516137ee9190614794565b898660400151838151811061380557613805614542565b6020026020010151613817919061463d565b6138219190614654565b608086015261387a565b8460200151818151811061384157613841614542565b60200260200101518560600181815250508460400151818151811061386857613868614542565b60200260200101518560800181815250505b878560600151108061388e57506080850151155b156138d65788888660a00151876020015184815181106138b0576138b0614542565b60200260200101516138c29190614794565b6138cc9190614794565b11613ae057613ad8565b84608001518d6001600160a01b0316630adb2d858760000151848151811061390057613900614542565b60200260200101518e89606001518f8b60800151306040518763ffffffff1660e01b815260040161393696959493929190614b7c565b6020604051808303816000875af1158015613955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139799190614575565b146040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906139c05760405162461bcd60e51b815260040161158391906147f7565b507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec856000015182815181106139f8576139f8614542565b60200260200101518c87606001518d896080015130604051613a1f96959493929190614b7c565b60405180910390a16080850151613a369087614794565b9550846060015187613a489190614794565b9650670de0b6b3a764000085608001518660e00151613a67919061463d565b613a719190614654565b60c086018190528290613a84908561463d565b613a8e9190614654565b60a086018190526060860151613aa391614794565b8911613ab0576000613ace565b84606001518560a00151613ac49190614794565b613ace908a61468a565b9850878910613ae0575b6001016136bc565b5050505b5050965096945050505050565b6000613b46826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dc99092919063ffffffff16565b8051909150156128c25780806020019051810190613b649190614cca565b6128c25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611583565b600080613bcf85610787565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613bff9190614676565b602060405180830381865afa158015613c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c409190614575565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613c709190614676565b602060405180830381865afa158015613c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb19190614575565b9050846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d159190614bb4565b613d2090600a614cbb565b82876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190614bb4565b613d8e90600a614cbb565b613da084670de0b6b3a764000061463d565b613daa919061463d565b613db49190614654565b613dbe9190614654565b979650505050505050565b6060613dd88484600085613de0565b949350505050565b606082471015613e415760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611583565b600080866001600160a01b03168587604051613e5d9190614db8565b60006040518083038185875af1925050503d8060008114613e9a576040519150601f19603f3d011682016040523d82523d6000602084013e613e9f565b606091505b5091509150613dbe8783838760608315613f1a578251600003613f13576001600160a01b0385163b613f135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611583565b5081613dd8565b613dd88383815115613f2f5781518083602001fd5b8060405162461bcd60e51b815260040161158391906147f7565b6001600160a01b0381168114613f5e57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613f9957613f99613f61565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613fc757613fc7613f61565b604052919050565b60006001600160401b03821115613fe857613fe8613f61565b5060051b60200190565b8035613ffd81613f49565b919050565b600082601f83011261401357600080fd5b8135602061402861402383613fcf565b613f9f565b82815260059290921b8401810191818101908684111561404757600080fd5b8286015b8481101561406b57803561405e81613f49565b835291830191830161404b565b509695505050505050565b600082601f83011261408757600080fd5b8135602061409761402383613fcf565b82815260059290921b840181019181810190868411156140b657600080fd5b8286015b8481101561406b57803583529183019183016140ba565b600080600080600080600060e0888a0312156140ec57600080fd5b87356140f781613f49565b96506020880135955060408801356001600160401b038082111561411a57600080fd5b6141268b838c01614002565b965060608a0135955060808a013591508082111561414357600080fd5b506141508a828b01614076565b93505060a0880135915060c0880135905092959891949750929550565b600081518084526020808501945080840160005b8381101561419d57815187529582019590820190600101614181565b509495945050505050565b60208152600061174e602083018461416d565b60008060008060008060c087890312156141d457600080fd5b86356141df81613f49565b955060208701356141ef81613f49565b945060408701359350606087013592506080870135915060a08701356001600160401b0381111561421f57600080fd5b61422b89828a01614002565b9150509295509295509295565b600080600080600080600060e0888a03121561425357600080fd5b873596506020880135955060408801356001600160401b038082111561427857600080fd5b6142848b838c01614002565b965060608a0135915061429682613f49565b9094506080890135935060a089013590808211156142b357600080fd5b6142bf8b838c01614002565b935060c08a01359150808211156142d557600080fd5b506142e28a828b01614076565b91505092959891949750929550565b8015158114613f5e57600080fd5b600080600080600080600080610100898b03121561431c57600080fd5b883561432781613f49565b9750602089013561433781613f49565b9650604089013561434781613f49565b9550606089013561435781613f49565b94506080890135935060a0890135925060c0890135915060e089013561437c816142f1565b809150509295985092959890939650565b600080600080608085870312156143a357600080fd5b84356143ae81613f49565b935060208501356143be81613f49565b925060408501356143ce81613f49565b9396929550929360600135925050565b60008060008060008060c087890312156143f757600080fd5b86356001600160401b0381111561440d57600080fd5b61441989828a01614002565b96505060208701359450604087013561443181613f49565b9350606087013561444181613f49565b9598949750929560808101359460a0909101359350915050565b60006001600160401b0382111561447457614474613f61565b50601f01601f191660200190565b60008060008060008060c0878903121561449b57600080fd5b86356144a681613f49565b955060208701356001600160401b038111156144c157600080fd5b8701601f810189136144d257600080fd5b80356144e06140238261445b565b8181528a60208385010111156144f557600080fd5b8160208401602083013760006020838301015280975050505061451a60408801613ff2565b935061452860608801613ff2565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561456a57600080fd5b815161174e81613f49565b60006020828403121561458757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810360008312801583831316838312821617156145c4576145c461458e565b5092915050565b600081518084526020808501945080840160005b8381101561419d5781516001600160a01b0316875295820195908201906001016145df565b60808152600061461760808301876145cb565b8281036020840152614629818761416d565b604084019590955250506060015292915050565b808202811582820484141761084c5761084c61458e565b60008261467157634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0391909116815260200190565b8181038181111561084c5761084c61458e565b8060005b60078110156128c05781518452602093840193909101906001016146a1565b60006101c0828a835b60028110156146f15781516001600160a01b03168352602092830192909101906001016146c9565b5050508060408401526147068184018a6145cb565b9050828103606084015261471a818961416d565b9050828103608084015261472e818861416d565b905082810360a0840152614742818761416d565b905082810360c0840152614756818661416d565b91505061020160e083018461469d565b60008060006060848603121561477b57600080fd5b8351925060208401519150604084015190509250925092565b8082018082111561084c5761084c61458e565b60005b838110156147c25781810151838201526020016147aa565b50506000910152565b600081518084526147e38160208601602086016147a7565b601f01601f19169290920160200192915050565b60208152600061174e60208301846147cb565b60808152600061481d60808301876145cb565b828103602084015261482f818761416d565b6001600160a01b03959095166040840152505090151560609091015292915050565b600082601f83011261486257600080fd5b81516148706140238261445b565b81815284602083860101111561488557600080fd5b613dd88260208301602087016147a7565b60008060408084860312156148aa57600080fd5b83516001600160401b03808211156148c157600080fd5b818601915086601f8301126148d557600080fd5b815160206148e561402383613fcf565b82815260079290921b8401810191818101908a84111561490457600080fd5b948201945b8386101561497e576080868c0312156149225760008081fd5b61492a613f77565b865161493581613f49565b81528684015161494481613f49565b818501528688015161495581613f49565b8189015260608781015161496881613f49565b9082015282526080959095019490820190614909565b9189015191975090945050508083111561499757600080fd5b50506149a585828601614851565b9150509250929050565b600080604083850312156149c257600080fd5b505080516020909101519092909150565b60a0815260006149e660a08301886147cb565b6001600160a01b03968716602084015260408301959095525091909316606082015260800191909152919050565b600082601f830112614a2557600080fd5b81516020614a3561402383613fcf565b82815260059290921b84018101918181019086841115614a5457600080fd5b8286015b8481101561406b5780518352918301918301614a58565b60008060008060808587031215614a8557600080fd5b84516001600160401b0380821115614a9c57600080fd5b818701915087601f830112614ab057600080fd5b81516020614ac061402383613fcf565b82815260059290921b8401810191818101908b841115614adf57600080fd5b948201945b83861015614b06578551614af781613f49565b82529482019490820190614ae4565b918a0151919850909350505080821115614b1f57600080fd5b614b2b88838901614a14565b94506040870151915080821115614b4157600080fd5b614b4d88838901614a14565b93506060870151915080821115614b6357600080fd5b50614b7087828801614a14565b91505092959194509250565b6001600160a01b039687168152948616602086015260408501939093529084166060840152608083015290911660a082015260c00190565b600060208284031215614bc657600080fd5b815160ff8116811461174e57600080fd5b600181815b80851115614c12578160001904821115614bf857614bf861458e565b80851615614c0557918102915b93841c9390800290614bdc565b509250929050565b600082614c295750600161084c565b81614c365750600061084c565b8160018114614c4c5760028114614c5657614c72565b600191505061084c565b60ff841115614c6757614c6761458e565b50506001821b61084c565b5060208310610133831016604e8410600b8410161715614c95575081810a61084c565b614c9f8383614bd7565b8060001904821115614cb357614cb361458e565b029392505050565b600061174e60ff841683614c1a565b600060208284031215614cdc57600080fd5b815161174e816142f1565b600060018201614cf957614cf961458e565b5060010190565b6060808252845182820181905260009190608090818501906020808a01865b83811015614d6757815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614d1f565b50508601979097526040909401949094525090949350505050565b60008060008060808587031215614d9857600080fd5b505082516020840151604085015160609095015191969095509092509050565b60008251614dca8184602087016147a7565b919091019291505056fea2646970667358221220669d32ba0e9feb65aa745e622b036eb00e94cb14444601c93e73ec2dd51dbfce64736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c80633542989d1461007c57806358b54f16146100b25780635dcb6130146100e05780637de8f56914610115578063954d7e7314610135578063c432aee114610155578063ca27d10d14610175575b600080fd5b81801561008857600080fd5b5061009c6100973660046140d1565b610195565b6040516100a991906141a8565b60405180910390f35b8180156100be57600080fd5b506100d26100cd3660046141bb565b61020d565b6040519081526020016100a9565b8180156100ec57600080fd5b506101006100fb366004614238565b610261565b604080519283526020830191909152016100a9565b81801561012157600080fd5b506101006101303660046142ff565b6106c4565b81801561014157600080fd5b5061010061015036600461438d565b6106e9565b81801561016157600080fd5b506100d26101703660046143de565b610705565b81801561018157600080fd5b50610100610190366004614482565b610766565b60606101ad87878686896101a88e610787565b610852565b9050610201888787846101fc8760008d8d815181106101ce576101ce614542565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054610a96565b610aae565b98975050505050505050565b600080825190506102016040518060a001604052808a6001600160a01b03168152602001896001600160a01b031681526020018581526020018881526020018381525061025b878685610d11565b86610da7565b6000806102e560405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001606081525090565b89546001600160a01b03908116825260018b01541660208083018290526040805163fbfa77cf60e01b8152905163fbfa77cf926004808401939192918290030181865afa15801561033a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035e9190614558565b6001600160a01b031660408083018290528051632273cc8160e21b815290516389cf3204916004808201926020929091908290030181865afa1580156103a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cc9190614558565b81606001906001600160a01b031690816001600160a01b03168152505088600301548160800181815250506104768a600301548b6004015483602001516001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610446573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046a9190614575565b84516060860151611755565b61012083015261010082015260408051610180810190915260018a01546001600160a01b03168152600090602081016104ae8a6118af565b6001600160a01b0316815260200183606001516001600160a01b0316815260200183600001516001600160a01b031681526020018a81526020018781526020016104fa89898a51610d11565b81526020018c60050154815260200186815260200183610100015181526020018360800151815260200161055589600086600001516001600160a01b03166001600160a01b0316815260200190815260200160002054610a96565b90529050610562816118ef565b60a085018190526101408501929092526080840151909450146106075760a082015160038b0181905560808301516040517fceb182d5d0a740eee7db26b536f6262ac3c83f61518a662039ec236f98c09d74926105c6928252602082015260400190565b60405180910390a160008260a0015183608001516105e491906145a4565b136105f0576000610604565b8160a00151826080015161060491906145a4565b93505b8151606083015160028d01546101208501516101608501516106399493889390926001600160a01b0390911691611cf7565b8360c0018460e00182815250828152505050610665888360400151888561014001518560c00151611d75565b610140840181905260c084015160e08501516040519399507f4c300a656bfa0935e36cd55e92634bc20b2b7e0a0ebf424a2a25bfaac3a01e76936106ae938b9390929091614604565b60405180910390a1505097509795505050505050565b6000806106d78a8a8a8a8a8a8a8a611f1c565b915091505b9850989650505050505050565b6000806106f886868686612026565b9150915094509492505050565b6040805160a0810182526001600160a01b038087168252851660208201529081018790526060810186905286516080820181905260009190829061074c9085908b90610d11565b9050610759828287610da7565b9998505050505050505050565b60008061077788888888888861215a565b915091505b965096945050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107eb9190614558565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061084c9190614558565b92915050565b8451606090806001600160401b0381111561086f5761086f613f61565b604051908082528060200260200182016040528015610898578160200160208202803683370190505b5091506000806108a9858a856125e3565b9150915060005b83811015610a88576000888a83815181106108cd576108cd614542565b60200260200101518d6108e0919061463d565b6108ea9190614654565b9050878203610917578086838151811061090657610906614542565b602002602001018181525050610a7f565b600083898151811061092b5761092b614542565b602002602001015185848151811061094557610945614542565b602002602001015185858151811061095f5761095f614542565b6020026020010151878c8151811061097957610979614542565b60200260200101518561098c919061463d565b610996919061463d565b6109a09190614654565b6109aa9190614654565b905060008c84815181106109c0576109c0614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016109f39190614676565b602060405180830381865afa158015610a10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a349190614575565b905081811015610a7c5781610a49828261468a565b610a53908561463d565b610a5d9190614654565b888581518110610a6f57610a6f614542565b6020026020010181815250505b50505b506001016108b0565b505050509695505050505050565b60008115610aa4578161084c565b620186a092915050565b8351606090806001600160401b03811115610acb57610acb613f61565b604051908082528060200260200182016040528015610af4578160200160208202803683370190505b5091506000868681518110610b0b57610b0b614542565b6020026020010151905060005b82811015610c5857868114610c50576000888281518110610b3b57610b3b614542565b60200260200101519050868281518110610b5757610b57614542565b6020026020010151600014610bc357610b8a83888481518110610b7c57610b7c614542565b60200260200101518c6127d1565b610bc08a6040518060200160405280600081525085848b8781518110610bb257610bb2614542565b60200260200101518b61215a565b50505b6040516370a0823160e01b81526001600160a01b038216906370a0823190610bef903090600401614676565b602060405180830381865afa158015610c0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c309190614575565b858381518110610c4257610c42614542565b602002602001018181525050505b600101610b18565b50610ce8858781518110610c6e57610c6e614542565b6020026020010151826001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610ca29190614676565b602060405180830381865afa158015610cbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce39190614575565b6128c7565b838781518110610cfa57610cfa614542565b602002602001018181525050505095945050505050565b6060816001600160401b03811115610d2b57610d2b613f61565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50905060005b82811015610d9f57610d7a8560008684815181106101ce576101ce614542565b828281518110610d8c57610d8c614542565b6020908102919091010152600101610d5a565b509392505050565b6000811561174e57610db8826128dd565b9150610e2960405180610180016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016060815260200160608152602001606081526020016000151581525090565b8460400151856060015181518110610e4357610e43614542565b60209081029190910101516001600160a01b0316815260808501516001600160401b03811115610e7557610e75613f61565b604051908082528060200260200182016040528015610e9e578160200160208202803683370190505b5061014082015280516040516370a0823160e01b81526001600160a01b03909116906370a0823190610ed4903090600401614676565b602060405180830381865afa158015610ef1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f159190614575565b9150610f36610f278660000151610787565b866040015187608001516125e3565b61012083015261010082015260005b856080015181101561174b57606086015181146117435781516040516370a0823160e01b81526001600160a01b03909116906370a0823190610f8b903090600401614676565b602060405180830381865afa158015610fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcc9190614575565b60208301526040860151805182908110610fe857610fe8614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161101b9190614676565b602060405180830381865afa158015611038573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105c9190614575565b60408301525b73__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b03168152508860400151888661010001518761012001518861014001516040518060e001604052806000815260200160008152602001600081526020018d81526020018f6060015181526020018a815260200160008152506040518863ffffffff1660e01b815260040161113297969594939291906146c0565b606060405180830381865af415801561114f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111739190614766565b60e085015260c084015260a08301819052158015611193575060e0820151155b61170f5760008260a001516000146113e357600060018460a001516111b8919061468a565b90506000886060015182146111d15788606001516111d3565b835b905061124789600001518a602001518b6040015185815181106111f8576111f8614542565b60200260200101518c60400151858151811061121657611216614542565b60200260200101518960c0015161012c8e898151811061123857611238614542565b60200260200101516000611f1c565b5060608a01519093508203611267576112608684612915565b95506113e0565b886060015181036113e057846101200151848151811061128957611289614542565b60200260200101518561010001518a60600151815181106112ac576112ac614542565b60200260200101518661012001518b60600151815181106112cf576112cf614542565b602002602001015187610100015187815181106112ee576112ee614542565b602002602001015186611301919061463d565b61130b919061463d565b6113159190614654565b61131f9190614654565b6113299087614794565b9550600085600001516001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161135d9190614676565b602060405180830381865afa15801561137a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139e9190614575565b905087898b60600151815181106113b7576113b7614542565b6020026020010151826113ca9190614794565b11156113de5760208601525061170f915050565b505b50505b60e0830151156115c857600060018460e00151611400919061468a565b905060008860600151821461141957886060015161141b565b835b905060008960400151838151811061143557611435614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016114689190614676565b602060405180830381865afa158015611485573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a99190614575565b905060008060006114fa8d600001518e6040015187815181106114ce576114ce614542565b60200260200101518f6040015189815181106114ec576114ec614542565b60200260200101518761292f565b9250925092508c60600151860361152a57808a11611519576000611523565b611523818b61468a565b99506115c1565b8c6060015185036115c15760408051808201909152601681527554532d32302062616c616e636520646563726561736560501b60208201528784101561158c5760405162461bcd60e51b815260040161158391906147f7565b60405180910390fd5b50808210156115b457806115a0838561463d565b6115aa9190614654565b611523908b614794565b6115be838b614794565b99505b5050505050505b82516040516370a0823160e01b81526001600160a01b03909116906370a08231906115f7903090600401614676565b602060405180830381865afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116389190614575565b6060840152604087015180518390811061165457611654614542565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116879190614676565b602060405180830381865afa1580156116a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c89190614575565b6080840152606083015160208401511480156116eb575082608001518360400151145b15801561016085015260608401516020850152608084015160408501529050611062575b838587606001518151811061172657611726614542565b6020026020010151836020015161173d9190614794565b1161174b575b600101610f45565b50505b9392505050565b60008080620186a0611769610bb88861463d565b6117739190614654565b90506000856001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016117a39190614676565b602060405180830381865afa1580156117c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e49190614575565b90506000620186a06117f68a8c61463d565b6118009190614654565b905060008383101580611811575083155b61185c57620186a0846118248c8361468a565b8d61182f878961468a565b611839919061463d565b611843919061463d565b61184d9190614654565b6118579190614654565b61185f565b60005b905061186b8183614794565b81156118975761187b8284614794565b61188884620186a061463d565b6118929190614654565b61189c565b620186a05b95509550505050505b9550959350505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610828573d6000803e3d6000fd5b606060008061193d6040518060e001604052806000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b60a080860151519082018190526101008601515160408051808201909152601281527154532d342077726f6e67206c656e6774687360701b602082015291146119995760405162461bcd60e51b815260040161158391906147f7565b508060a001516001600160401b038111156119b6576119b6613f61565b6040519080825280602002602001820160405280156119df578160200160208202803683370190505b50935060005b8160a00151811015611ce8578561016001518661014001511315611a7f57611a138682886101400151612b00565b8761010001518381518110611a2a57611a2a614542565b6101408a0192909252602091820201015260c0860151805182908110611a5257611a52614542565b60200260200101518661010001518281518110611a7157611a71614542565b602002602001015110611ce0575b620186a0866101200151620186a0611a97919061468a565b8761010001518381518110611aae57611aae614542565b6020026020010151611ac0919061463d565b611aca9190614654565b6060830181905260e0870151620186a091611ae5919061463d565b611aef9190614654565b60208301526060820151610100870151805183908110611b1157611b11614542565b6020026020010151611b23919061468a565b604083015260a0860151805182908110611b3f57611b3f614542565b6020908102919091018101516001600160a01b03166080840152604083015190830151611b6c9190614794565b80835215611cad57600019611b8987608001518460800151612e13565b14611c0c5785606001516001600160a01b031682608001516001600160a01b031603611bc5576040820151611bbe9085614794565b9350611cad565b611bfa866000015187602001518460800151896060015186604001516113888c60c00151888151811061123857611238614542565b60c08401819052611bbe915085614794565b611c50866000015187602001518460800151896060015186600001516113888c60c001518881518110611c4157611c41614542565b60200260200101516001611f1c565b60c08401525081516060830151610100880151805184908110611c7557611c75614542565b6020026020010151611c87919061468a565b8360c00151611c96919061463d565b611ca09190614654565b611caa9085614794565b93505b81602001518260600151611cc1919061468a565b858281518110611cd357611cd3614542565b6020026020010181815250505b6001016119e5565b50505061014092909201519092565b600080620186a0611d08858961463d565b611d129190614654565b9150611d1e828861468a565b90508115611d4b5782821015611d375760009150611d4b565b611d4b6001600160a01b0389168684612e71565b801561077c5782811015611d615750600061077c565b61077c6001600160a01b0389168783612e71565b6060806000855190506000886001600160a01b031663f645d4f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de29190614558565b905060005b82811015611e9357868181518110611e0157611e01614542565b6020026020010151868281518110611e1b57611e1b614542565b60200260200101511115611e4e576000878281518110611e3d57611e3d614542565b602002602001018181525050611e8b565b611e8b888281518110611e6357611e63614542565b6020026020010151888381518110611e7d57611e7d614542565b6020026020010151846127d1565b600101611de7565b50611e9e8787612ec3565b8151919550935015611f1057604051637e0ddbef60e01b81526001600160a01b03821690637e0ddbef90611edd90879087908d9060019060040161480a565b600060405180830381600087803b158015611ef757600080fd5b505af1158015611f0b573d6000803e3d6000fd5b505050505b50509550959350505050565b600080838611611f31575060009050806106dc565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa158015611f83573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611fab9190810190614896565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506120025760405162461bcd60e51b815260040161158391906147f7565b50866120148c838d8d8d8d8d8c6130b1565b92509250509850989650505050505050565b6000806000846001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120579190614676565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614575565b60405163dd27ede760e01b81523060048201526001600160a01b03888116602483015287811660448301526001606483015291925060009189169063dd27ede79060840160408051808303816000875af11580156120fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211e91906149af565b509050600061213b8287106121335782612135565b865b846128c7565b905061214a89898984876133a1565b9450945050505094509492505050565b6000808260000361216a57600a92505b82841161217c5750600090508061077c565b6121b56040518060c001604052806000815260200160608152602001606081526020016060815260200160008152602001600081525090565b6121be8861358a565b808252600019016121e1576121d78989898989896135b1565b925092505061077c565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790612218908b908b908a908c906213c680906004016149d3565b600060405180830381865afa158015612235573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261225d9190810190614a6f565b5060608401526040830152602082018190525180156125dc5760005b818110156125da578251612389578260400151818151811061229d5761229d614542565b602002602001015187106122ce57826040015181815181106122c1576122c1614542565b60200260200101516122d0565b865b608084015260408301518051829081106122ec576122ec614542565b6020026020010151871061231d578260600151818151811061231057612310614542565b602002602001015161236e565b8260400151818151811061233357612333614542565b6020026020010151878460600151838151811061235257612352614542565b6020026020010151612364919061463d565b61236e9190614654565b60a08401526080830151612382908861468a565b9650612487565b8260600151818151811061239f5761239f614542565b602002602001015187106123d057826060015181815181106123c3576123c3614542565b60200260200101516123d2565b865b60a084015260608301518051829081106123ee576123ee614542565b6020026020010151871061241f578260400151818151811061241257612412614542565b6020026020010151612470565b8260600151818151811061243557612435614542565b6020026020010151878460400151838151811061245457612454614542565b6020026020010151612466919061463d565b6124709190614654565b608084015260a0830151612484908861468a565b96505b858710801561249557508615155b1561249f57600096505b60a0830151156125cc578a6001600160a01b0316630adb2d85846020015183815181106124ce576124ce614542565b60200260200101518b86608001518c8860a00151306040518763ffffffff1660e01b815260040161250496959493929190614b7c565b6020604051808303816000875af1158015612523573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125479190614575565b6125519085614794565b93508260800151856125639190614794565b94507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec8360200151828151811061259c5761259c614542565b60200260200101518a85608001518b8760a00151306040516125c396959493929190614b7c565b60405180910390a15b86156125da57600101612279565b505b505061077c565b606080826001600160401b038111156125fe576125fe613f61565b604051908082528060200260200182016040528015612627578160200160208202803683370190505b509150826001600160401b0381111561264257612642613f61565b60405190808252806020026020018201604052801561266b578160200160208202803683370190505b50905060005b838110156127c85784818151811061268b5761268b614542565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f49190614bb4565b6126ff90600a614cbb565b82828151811061271157612711614542565b602002602001018181525050856001600160a01b031663b3596f0786838151811061273e5761273e614542565b60200260200101516040518263ffffffff1660e01b81526004016127629190614676565b602060405180830381865afa15801561277f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a39190614575565b8382815181106127b5576127b5614542565b6020908102919091010152600101612671565b50935093915050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa158015612820573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128449190614575565b10156128c25760405163095ea7b360e01b81526001600160a01b038281166004830152600160ff1b602483015284169063095ea7b3906044016020604051808303816000875af115801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c09190614cca565b505b505050565b60008183106128d6578161174e565b5090919050565b6000600019821461291157620186a06128f861138882614794565b612902908461463d565b61290c9190614654565b61084c565b5090565b600081831161292557600061174e565b61174e828461468a565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016129619190614676565b602060405180830381865afa15801561297e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129a29190614575565b60405163dd27ede760e01b81523060048201526001600160a01b0389811660248301528881166044830152600160648301529192506000918a169063dd27ede79060840160408051808303816000875af1158015612a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a2891906149af565b509050612a43818710612a3b5781612a3d565b865b836128c7565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015612aa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ac991906149af565b909650905080861115612ae357612ae0818761468a565b95505b612af08a8a8a87876133a1565b9550505050509450945094915050565b6000806000808660a001518681518110612b1c57612b1c614542565b60200260200101516001600160a01b031687606001516001600160a01b031603612b7257612b68858861010001518881518110612b5b57612b5b614542565b60200260200101516128c7565b9150819050612d3b565b60008761016001518861010001518881518110612b9157612b91614542565b602002602001015111612ba5576000612c73565b87602001516001600160a01b031663a9dd14d68960a001518981518110612bce57612bce614542565b60200260200101518a606001518b61010001518b81518110612bf257612bf2614542565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614575565b9050600088610160015187612c889190614794565b8211612cb2578861010001518881518110612ca557612ca5614542565b6020026020010151612ce7565b81878a61010001518a81518110612ccb57612ccb614542565b6020026020010151612cdd919061463d565b612ce79190614654565b9050612d3389600001518a602001518b60a001518b81518110612d0c57612d0c614542565b60200260200101518c60600151856113888f60c001518f81518110611c4157611c41614542565b909450925050505b612d6187604001518289606001516001600160a01b0316612e719092919063ffffffff16565b612d898761010001518781518110612d7b57612d7b614542565b602002602001015183612915565b9350612d9581866145a4565b92507f25f353a73b632dcffa5ff4f0edc2f19635d557167df35e97b06545b3f4bd3e8b8760a001518781518110612dce57612dce614542565b602090810291909101810151604080516001600160a01b0390921682529181018590529081018790526060810185905260800160405180910390a15050935093915050565b8151600090815b81811015612e6557836001600160a01b0316858281518110612e3e57612e3e614542565b60200260200101516001600160a01b031603612e5d57915061084c9050565b600101612e1a565b50600019949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526128c2908490613af1565b60608082518451146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090612f0f5760405162461bcd60e51b815260040161158391906147f7565b508351600090815b81811015612f6057858181518110612f3157612f31614542565b6020026020010151600014612f4e5782612f4a81614ce7565b9350505b80612f5881614ce7565b915050612f17565b50816001600160401b03811115612f7957612f79613f61565b604051908082528060200260200182016040528015612fa2578160200160208202803683370190505b509350816001600160401b03811115612fbd57612fbd613f61565b604051908082528060200260200182016040528015612fe6578160200160208202803683370190505b5092506000805b828110156130a657600087828151811061300957613009614542565b60200260200101519050806000146130935788828151811061302d5761302d614542565b602002602001015187848151811061304757613047614542565b60200260200101906001600160a01b031690816001600160a01b0316815250508086848151811061307a5761307a614542565b60209081029190910101528261308f81614ce7565b9350505b508061309e81614ce7565b915050612fed565b505050509250929050565b60006130be8685896127d1565b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906130ed903090600401614676565b602060405180830381865afa15801561310a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312e9190614575565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890613161908c9089908990600401614d00565b600060405180830381600087803b15801561317b57600080fd5b505af115801561318f573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a08231906131c2903090600401614676565b602060405180830381865afa1580156131df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132039190614575565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906132555760405162461bcd60e51b815260040161158391906147f7565b50613260828261468a565b925083806132f05750604051630a47e27160e21b81526001600160a01b03898116600483015260248201889052888116604483015260648201859052608482018790528c169063291f89c49060a401602060405180830381865afa1580156132cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f09190614cca565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906133395760405162461bcd60e51b815260040161158391906147f7565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b600080606484106118a5576133c06001600160a01b0386168886612e71565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af1158015613421573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134459190614d82565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906134da903090600401614676565b602060405180830381865afa1580156134f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351b9190614575565b905080851161352b576000613535565b613535818661468a565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b6020820152909350821561357d5760405162461bcd60e51b815260040161158391906147f7565b5050509550959350505050565b6000815160000361359d57506000919050565b8180602001905181019061084c9190614575565b6000806135fc60405180610100016040528060608152602001606081526020016060815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405163430ffb1760e01b81526001600160a01b038a169063430ffb1790613633908b908b908a908c906213c680906004016149d3565b600060405180830381865afa158015613650573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526136789190810190614a6f565b5060408401526020830152808252518015613ae4576000808a8060200190518101906136a49190614766565b92509250506136b48c8b8b613bc3565b60e085015260005b83811015613ae057670de0b6b3a7640000856040015182815181106136e3576136e3614542565b60200260200101518660e001516136fa919061463d565b6137049190614654565b60c086018190528290613717908561463d565b6137219190614654565b60a08601819052602086015180518b9291908490811061374357613743614542565b60200260200101516137559190614794565b111561382b578460a001518560200151828151811061377657613776614542565b60200260200101516137889190614794565b898660200151838151811061379f5761379f614542565b60200260200101516137b1919061463d565b6137bb9190614654565b606086015260a085015160208601518051839081106137dc576137dc614542565b60200260200101516137ee9190614794565b898660400151838151811061380557613805614542565b6020026020010151613817919061463d565b6138219190614654565b608086015261387a565b8460200151818151811061384157613841614542565b60200260200101518560600181815250508460400151818151811061386857613868614542565b60200260200101518560800181815250505b878560600151108061388e57506080850151155b156138d65788888660a00151876020015184815181106138b0576138b0614542565b60200260200101516138c29190614794565b6138cc9190614794565b11613ae057613ad8565b84608001518d6001600160a01b0316630adb2d858760000151848151811061390057613900614542565b60200260200101518e89606001518f8b60800151306040518763ffffffff1660e01b815260040161393696959493929190614b7c565b6020604051808303816000875af1158015613955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139799190614575565b146040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906139c05760405162461bcd60e51b815260040161158391906147f7565b507ff63c9c64ebdd1eb99706ca3f7489f7fbdd9c8756363cef40b2fc6e293fa150ec856000015182815181106139f8576139f8614542565b60200260200101518c87606001518d896080015130604051613a1f96959493929190614b7c565b60405180910390a16080850151613a369087614794565b9550846060015187613a489190614794565b9650670de0b6b3a764000085608001518660e00151613a67919061463d565b613a719190614654565b60c086018190528290613a84908561463d565b613a8e9190614654565b60a086018190526060860151613aa391614794565b8911613ab0576000613ace565b84606001518560a00151613ac49190614794565b613ace908a61468a565b9850878910613ae0575b6001016136bc565b5050505b5050965096945050505050565b6000613b46826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dc99092919063ffffffff16565b8051909150156128c25780806020019051810190613b649190614cca565b6128c25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611583565b600080613bcf85610787565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613bff9190614676565b602060405180830381865afa158015613c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c409190614575565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b8152600401613c709190614676565b602060405180830381865afa158015613c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb19190614575565b9050846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d159190614bb4565b613d2090600a614cbb565b82876001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d839190614bb4565b613d8e90600a614cbb565b613da084670de0b6b3a764000061463d565b613daa919061463d565b613db49190614654565b613dbe9190614654565b979650505050505050565b6060613dd88484600085613de0565b949350505050565b606082471015613e415760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611583565b600080866001600160a01b03168587604051613e5d9190614db8565b60006040518083038185875af1925050503d8060008114613e9a576040519150601f19603f3d011682016040523d82523d6000602084013e613e9f565b606091505b5091509150613dbe8783838760608315613f1a578251600003613f13576001600160a01b0385163b613f135760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611583565b5081613dd8565b613dd88383815115613f2f5781518083602001fd5b8060405162461bcd60e51b815260040161158391906147f7565b6001600160a01b0381168114613f5e57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613f9957613f99613f61565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613fc757613fc7613f61565b604052919050565b60006001600160401b03821115613fe857613fe8613f61565b5060051b60200190565b8035613ffd81613f49565b919050565b600082601f83011261401357600080fd5b8135602061402861402383613fcf565b613f9f565b82815260059290921b8401810191818101908684111561404757600080fd5b8286015b8481101561406b57803561405e81613f49565b835291830191830161404b565b509695505050505050565b600082601f83011261408757600080fd5b8135602061409761402383613fcf565b82815260059290921b840181019181810190868411156140b657600080fd5b8286015b8481101561406b57803583529183019183016140ba565b600080600080600080600060e0888a0312156140ec57600080fd5b87356140f781613f49565b96506020880135955060408801356001600160401b038082111561411a57600080fd5b6141268b838c01614002565b965060608a0135955060808a013591508082111561414357600080fd5b506141508a828b01614076565b93505060a0880135915060c0880135905092959891949750929550565b600081518084526020808501945080840160005b8381101561419d57815187529582019590820190600101614181565b509495945050505050565b60208152600061174e602083018461416d565b60008060008060008060c087890312156141d457600080fd5b86356141df81613f49565b955060208701356141ef81613f49565b945060408701359350606087013592506080870135915060a08701356001600160401b0381111561421f57600080fd5b61422b89828a01614002565b9150509295509295509295565b600080600080600080600060e0888a03121561425357600080fd5b873596506020880135955060408801356001600160401b038082111561427857600080fd5b6142848b838c01614002565b965060608a0135915061429682613f49565b9094506080890135935060a089013590808211156142b357600080fd5b6142bf8b838c01614002565b935060c08a01359150808211156142d557600080fd5b506142e28a828b01614076565b91505092959891949750929550565b8015158114613f5e57600080fd5b600080600080600080600080610100898b03121561431c57600080fd5b883561432781613f49565b9750602089013561433781613f49565b9650604089013561434781613f49565b9550606089013561435781613f49565b94506080890135935060a0890135925060c0890135915060e089013561437c816142f1565b809150509295985092959890939650565b600080600080608085870312156143a357600080fd5b84356143ae81613f49565b935060208501356143be81613f49565b925060408501356143ce81613f49565b9396929550929360600135925050565b60008060008060008060c087890312156143f757600080fd5b86356001600160401b0381111561440d57600080fd5b61441989828a01614002565b96505060208701359450604087013561443181613f49565b9350606087013561444181613f49565b9598949750929560808101359460a0909101359350915050565b60006001600160401b0382111561447457614474613f61565b50601f01601f191660200190565b60008060008060008060c0878903121561449b57600080fd5b86356144a681613f49565b955060208701356001600160401b038111156144c157600080fd5b8701601f810189136144d257600080fd5b80356144e06140238261445b565b8181528a60208385010111156144f557600080fd5b8160208401602083013760006020838301015280975050505061451a60408801613ff2565b935061452860608801613ff2565b92506080870135915060a087013590509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561456a57600080fd5b815161174e81613f49565b60006020828403121561458757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810360008312801583831316838312821617156145c4576145c461458e565b5092915050565b600081518084526020808501945080840160005b8381101561419d5781516001600160a01b0316875295820195908201906001016145df565b60808152600061461760808301876145cb565b8281036020840152614629818761416d565b604084019590955250506060015292915050565b808202811582820484141761084c5761084c61458e565b60008261467157634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0391909116815260200190565b8181038181111561084c5761084c61458e565b8060005b60078110156128c05781518452602093840193909101906001016146a1565b60006101c0828a835b60028110156146f15781516001600160a01b03168352602092830192909101906001016146c9565b5050508060408401526147068184018a6145cb565b9050828103606084015261471a818961416d565b9050828103608084015261472e818861416d565b905082810360a0840152614742818761416d565b905082810360c0840152614756818661416d565b91505061020160e083018461469d565b60008060006060848603121561477b57600080fd5b8351925060208401519150604084015190509250925092565b8082018082111561084c5761084c61458e565b60005b838110156147c25781810151838201526020016147aa565b50506000910152565b600081518084526147e38160208601602086016147a7565b601f01601f19169290920160200192915050565b60208152600061174e60208301846147cb565b60808152600061481d60808301876145cb565b828103602084015261482f818761416d565b6001600160a01b03959095166040840152505090151560609091015292915050565b600082601f83011261486257600080fd5b81516148706140238261445b565b81815284602083860101111561488557600080fd5b613dd88260208301602087016147a7565b60008060408084860312156148aa57600080fd5b83516001600160401b03808211156148c157600080fd5b818601915086601f8301126148d557600080fd5b815160206148e561402383613fcf565b82815260079290921b8401810191818101908a84111561490457600080fd5b948201945b8386101561497e576080868c0312156149225760008081fd5b61492a613f77565b865161493581613f49565b81528684015161494481613f49565b818501528688015161495581613f49565b8189015260608781015161496881613f49565b9082015282526080959095019490820190614909565b9189015191975090945050508083111561499757600080fd5b50506149a585828601614851565b9150509250929050565b600080604083850312156149c257600080fd5b505080516020909101519092909150565b60a0815260006149e660a08301886147cb565b6001600160a01b03968716602084015260408301959095525091909316606082015260800191909152919050565b600082601f830112614a2557600080fd5b81516020614a3561402383613fcf565b82815260059290921b84018101918181019086841115614a5457600080fd5b8286015b8481101561406b5780518352918301918301614a58565b60008060008060808587031215614a8557600080fd5b84516001600160401b0380821115614a9c57600080fd5b818701915087601f830112614ab057600080fd5b81516020614ac061402383613fcf565b82815260059290921b8401810191818101908b841115614adf57600080fd5b948201945b83861015614b06578551614af781613f49565b82529482019490820190614ae4565b918a0151919850909350505080821115614b1f57600080fd5b614b2b88838901614a14565b94506040870151915080821115614b4157600080fd5b614b4d88838901614a14565b93506060870151915080821115614b6357600080fd5b50614b7087828801614a14565b91505092959194509250565b6001600160a01b039687168152948616602086015260408501939093529084166060840152608083015290911660a082015260c00190565b600060208284031215614bc657600080fd5b815160ff8116811461174e57600080fd5b600181815b80851115614c12578160001904821115614bf857614bf861458e565b80851615614c0557918102915b93841c9390800290614bdc565b509250929050565b600082614c295750600161084c565b81614c365750600061084c565b8160018114614c4c5760028114614c5657614c72565b600191505061084c565b60ff841115614c6757614c6761458e565b50506001821b61084c565b5060208310610133831016604e8410600b8410161715614c95575081810a61084c565b614c9f8383614bd7565b8060001904821115614cb357614cb361458e565b029392505050565b600061174e60ff841683614c1a565b600060208284031215614cdc57600080fd5b815161174e816142f1565b600060018201614cf957614cf961458e565b5060010190565b6060808252845182820181905260009190608090818501906020808a01865b83811015614d6757815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614d1f565b50508601979097526040909401949094525090949350505050565b60008060008060808587031215614d9857600080fd5b505082516020840151604085015160609095015191969095509092509050565b60008251614dca8184602087016147a7565b919091019291505056fea2646970667358221220669d32ba0e9feb65aa745e622b036eb00e94cb14444601c93e73ec2dd51dbfce64736f6c63430008110033", "libraries": { "IterationPlanLib": "0x0118015B5D5F7f104292DB79Ae47AA0e962A09be" }, diff --git a/deployments/matic/PairBasedStrategyLib.json b/deployments/matic/PairBasedStrategyLib.json index a9dafe9b..f259fee5 100644 --- a/deployments/matic/PairBasedStrategyLib.json +++ b/deployments/matic/PairBasedStrategyLib.json @@ -1,5 +1,5 @@ { - "address": "0xE5779B35180c1048562c733A7E62f8Fe1d253C41", + "address": "0xE0D8b85C7Feb11b26e5A2466931088eC5DE7A703", "abi": [ { "anonymous": false, @@ -538,46 +538,46 @@ "type": "function" } ], - "transactionHash": "0x6168fa2e05dc12b4e9d5884f6b91d6a658b4fdc9f73e9c65b824bb777874765f", + "transactionHash": "0xa3aabe16015cf53597dd321dd73d710a0e186c1e27dccbb164a71ba1c2f6baad", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0xE5779B35180c1048562c733A7E62f8Fe1d253C41", - "transactionIndex": 91, + "contractAddress": "0xE0D8b85C7Feb11b26e5A2466931088eC5DE7A703", + "transactionIndex": 16, "gasUsed": "4058701", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0xdb9c425b46251ddfa76d7559e75b65133265c8b0101af762278e8e722ea34794", - "transactionHash": "0x6168fa2e05dc12b4e9d5884f6b91d6a658b4fdc9f73e9c65b824bb777874765f", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000800000000000000000000000000000800000000000000000000100000000000100000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000040001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0x2c35abdae533dbd8c2aa33c1e115e896439f6961c3b8610812f332827c6f2bb1", + "transactionHash": "0xa3aabe16015cf53597dd321dd73d710a0e186c1e27dccbb164a71ba1c2f6baad", "logs": [ { - "transactionIndex": 91, - "blockNumber": 54803193, - "transactionHash": "0x6168fa2e05dc12b4e9d5884f6b91d6a658b4fdc9f73e9c65b824bb777874765f", + "transactionIndex": 16, + "blockNumber": 55572318, + "transactionHash": "0xa3aabe16015cf53597dd321dd73d710a0e186c1e27dccbb164a71ba1c2f6baad", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x000000000000000000000000b95d435df3f8b2a8d8b9c2b7c8766c9ae6ed8cc9" ], - "data": "0x0000000000000000000000000000000000000000000000000015a10cf30823000000000000000000000000000000000000000000000000026bcf786573e6cba2000000000000000000000000000000000000000000002435d149f7fd2e71171e0000000000000000000000000000000000000000000000026bb9d75880dea8a2000000000000000000000000000000000000000000002435d15f990a21793a1e", - "logIndex": 350, - "blockHash": "0xdb9c425b46251ddfa76d7559e75b65133265c8b0101af762278e8e722ea34794" + "data": "0x00000000000000000000000000000000000000000000000002c9b7b555ab441b000000000000000000000000000000000000000000000001e0cda3555309b67c0000000000000000000000000000000000000000000000145506cb9b64f535fc000000000000000000000000000000000000000000000001de03eb9ffd5e726100000000000000000000000000000000000000000000001457d08350baa07a17", + "logIndex": 32, + "blockHash": "0x2c35abdae533dbd8c2aa33c1e115e896439f6961c3b8610812f332827c6f2bb1" } ], - "blockNumber": 54803193, - "cumulativeGasUsed": "19111330", + "blockNumber": 55572318, + "cumulativeGasUsed": "5655365", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 15, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fuseStatus\",\"type\":\"uint256\"}],\"name\":\"FuseStatusChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"newFuseThresholds\",\"type\":\"uint256[4]\"}],\"name\":\"NewFuseThresholds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToSwap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expectedAmountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetIn\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetOut\",\"type\":\"address\"}],\"name\":\"SwapByAgg\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ENTRY_TO_POOL_IS_ALLOWED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_LOWER_LIMIT_OFF\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_LOWER_LIMIT_ON\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_UPPER_LIMIT_OFF\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_UPPER_LIMIT_ON\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GAP_AMOUNT_TO_SWAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_POOL\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_TOKEN_A\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_TOKEN_B\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_FUSE_STATUS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_2\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_3\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_4\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_2\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_3\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_LOWER_TICK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_TICK_SPACING\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_UPPER_TICK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_ASSET\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_REBALANCE_TICK_RANGE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_TICK_RANGE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNKNOWN_SWAP_ROUTER\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolPriceDecimals\",\"type\":\"uint256\"}],\"name\":\"getPoolPriceAdjustment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"adjustment\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The library contains quoteWithdrawStep/withdrawStep-related logic\",\"kind\":\"dev\",\"methods\":{\"quoteWithdrawStep(address[2],address[],uint256[],uint256[],uint256,uint256[2])\":{\"params\":{\"amountsFromPool\":\"Amounts of {tokens} that will be received from the pool before calling withdraw\",\"converterLiquidator_\":\"[TetuConverter, TetuLiquidator]\",\"entryDataValues\":\"[propNotUnderlying18, entryDataParam] propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18]. The leftovers should be swapped to get following result proportions of the assets: not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18 Value type(uint).max means that the proportions should be read from the pool. entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\",\"liquidationThresholds\":\"Liquidation thresholds for the {tokens}\",\"tokens\":\"Tokens used by depositor (length == 2: underlying and not-underlying)\"},\"returns\":{\"amountToSwap\":\"Amount that will be swapped on the next swap. 0 - no swap This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\",\"tokenToSwap\":\"Address of the token that will be swapped on the next swap. 0 - no swap\"}},\"withdrawStep(address[2],address[],uint256[],address,uint256,address,bytes,bool,uint256,uint256[2])\":{\"params\":{\"aggregator_\":\"Aggregator that should be used for the next swap. 0 - no swap\",\"amountToSwap_\":\"Amount that will be swapped on the next swap. 0 - no swap\",\"converterLiquidator_\":\"[TetuConverter, TetuLiquidator]\",\"entryDataValues\":\"[propNotUnderlying18, entryDataParam] propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18]. The leftovers should be swapped to get following result proportions of the assets: not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18 entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\",\"liquidationThresholds\":\"Liquidation thresholds for the {tokens}\",\"planKind\":\"One of IterationPlanLib.PLAN_XXX\",\"swapData_\":\"Swap data to be passed to the aggregator on the next swap. Swap data contains swap-route, amount and all other required info for the swap. Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\",\"tokenToSwap_\":\"Address of the token that will be swapped on the next swap. 0 - no swap\",\"tokens\":\"Tokens used by depositor (length == 2: underlying and not-underlying)\",\"useLiquidator_\":\"Use liquidator instead of aggregator. Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}. Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}. It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false - the liquidator will be used in same way as aggregator in this case.\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to the required proportions\"}}},\"stateVariables\":{\"OPENOCEAN\":{\"details\":\"See https://docs.openocean.finance/dev/contracts-of-chains\"},\"OPENOCEAN_ZKEVM\":{\"details\":\"See https://docs.openocean.finance/dev/contracts-of-chains\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"ENTRY_TO_POOL_IS_ALLOWED()\":{\"notice\":\"Enter to the pool at the end of withdrawByAggStep\"},\"ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED()\":{\"notice\":\"Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\"},\"FUSE_IDX_LOWER_LIMIT_ON()\":{\"notice\":\"Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF] If the price falls below LOWER_LIMIT_ON the fuse is turned ON When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF Example: [0.9, 0.92, 1.08, 1.1] Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF. Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\"},\"GAP_AMOUNT_TO_SWAP()\":{\"notice\":\"A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\"},\"quoteWithdrawStep(address[2],address[],uint256[],uint256[],uint256,uint256[2])\":{\"notice\":\"Get info for the swap that will be made on the next call of {withdrawStep}\"},\"withdrawStep(address[2],address[],uint256[],address,uint256,address,bytes,bool,uint256,uint256[2])\":{\"notice\":\"Make withdraw step with 0 or 1 swap only. The step can make one of the following actions: 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\"}},\"notice\":\"Library for the UniV3-like strategies with two tokens in the pool\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyLib.sol\":\"PairBasedStrategyLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x61486c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102475760003560e01c8063767e17e811610145578063c143e087116100c2578063d7a1d53511610086578063d7a1d535146102e8578063e0c24b3a1461042e578063e642319514610436578063ec88f9ff146102a2578063f7ebc365146102a257600080fd5b8063c143e08714610313578063c63891c7146102a2578063c8ce726c146102e0578063cdb549351461041e578063d3a9335c1461042657600080fd5b8063a200f62b11610109578063a200f62b146102e0578063a7231ef6146103da578063aea02d91146103e2578063c00d3e0b146102e8578063c06ab65f146103ea57600080fd5b8063767e17e8146102e0578063831fd9ea146103135780638f875cc814610313578063927154f0146103a75780639c2d8d63146102e857600080fd5b806337d11dc1116101d357806360339c591161019757806360339c59146102e8578063603938b814610313578063673d63db1461031b5780636bffb346146103575780637545be261461037757600080fd5b806337d11dc1146102e857806343fc304a146102f057806346326a29146102f8578063556ce728146103005780635be05524146102e057600080fd5b8063137c52b21161021a578063137c52b2146102a25780631429888b146102aa57806314ad109e146102b2578063217052d1146102a257806335f33bc2146102e057600080fd5b8063058ba3db1461024c5780630593c4c91461026a5780631033193e1461028c5780631200fb3c146102a2575b600080fd5b61025461043e565b6040516102619190613b3f565b60405180910390f35b81801561027657600080fd5b5061028a610285366004613be2565b61045a565b005b610294600981565b604051908152602001610261565b610294600181565b610294600781565b8180156102be57600080fd5b506102d26102cd366004613e23565b6105f6565b604051610261929190613ed7565b610294600281565b610294600081565b610294600c81565b610294600a81565b61029461030e366004613ef0565b610758565b610294600381565b6102546040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525081565b81801561036357600080fd5b5061028a610372366004613f09565b610785565b81801561038357600080fd5b50610397610392366004613fce565b6107e9565b6040519015158152602001610261565b610254604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b81525081565b610294600b81565b610294600581565b61025460405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525081565b610294606481565b610294600481565b610294600681565b610294600881565b6040518060600160405280602281526020016148156022913981565b805115801561046b57506020810151155b8061047b57506020810151815111155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906104ce5760405162461bcd60e51b81526004016104c59190613b3f565b60405180910390fd5b5060408101511580156104e357506060810151155b806104f657506060810151604082015110155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906105405760405162461bcd60e51b81526004016104c59190613b3f565b508051158015906105545750604081015115155b156105ab5780516040808301518151808301909252601382527254532d333020696e76616c69642076616c756560681b60208301529091106105a95760405162461bcd60e51b81526004016104c59190613b3f565b505b6105ba60018301826004613a9c565b507fef6880b7ef7308e1a0fdc54890042b9fc1d2355795cd67a12c76d38438e643b5816040516105ea91906140d7565b60405180910390a15050565b600080808061061661060e8b835b60200201516109b6565b8a6002610a7b565b9150915060006040518061016001604052808c60006002811061063b5761063b6140c1565b60200201516001600160a01b031681526020018c600160028110610661576106616140c1565b60200201516001600160a01b031681526020018b81526020018a8152602001848152602001838152602001898152602001888152602001600019886000600281106106ae576106ae6140c1565b6020020151146106bf578751610721565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107219190614108565b8152875160001914602082015260400187600160200201519052905061074681610c69565b94509450505050965096945050505050565b60006012821061076957600161077f565b610774826012614137565b61077f90600a61422e565b92915050565b81548190839060ff191660018360038111156107a3576107a361423a565b02179055507f5a7ee3c5ef7f4e3625ee638c3a95481dc4cbfaceda022d1e8fba8ed7fa2208e18160038111156107db576107db61423a565b6040519081526020016105ea565b600080806108026107fa8e83610604565b8d6002610a7b565b9150915060006040518061016001604052808f600060028110610827576108276140c1565b60200201516001600160a01b031681526020018f60016002811061084d5761084d6140c1565b60200201516001600160a01b031681526020018e81526020018d815260200184815260200183815260200160026001600160401b0381111561089157610891613b52565b6040519080825280602002602001820160405280156108ba578160200160208202803683370190505b508152602081018890528651604090910190600019146108db57865161093d565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093d9190614108565b815286516000191460208201526040018660016020020151815250905060006040518060a0016040528089151581526020018d6001600160a01b031681526020018b6001600160a01b031681526020018c81526020018a81525090506109a38282610ddc565b9f9e505050505050505050505050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1a9190614250565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a57573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614250565b606080826001600160401b03811115610a9657610a96613b52565b604051908082528060200260200182016040528015610abf578160200160208202803683370190505b509150826001600160401b03811115610ada57610ada613b52565b604051908082528060200260200182016040528015610b03578160200160208202803683370190505b50905060005b83811015610c6057848181518110610b2357610b236140c1565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c919061426d565b610b9790600a614290565b828281518110610ba957610ba96140c1565b602002602001018181525050856001600160a01b031663b3596f07868381518110610bd657610bd66140c1565b60200260200101516040518263ffffffff1660e01b8152600401610bfa919061429f565b602060405180830381865afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3b9190614108565b838281518110610c4d57610c4d6140c1565b6020908102919091010152600101610b09565b50935093915050565b6000806000730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528087600001516001600160a01b03166001600160a01b0316815260200187602001516001600160a01b03166001600160a01b03168152508660400151876060015188608001518960a001518a60c001516040518060e001604052808d6101200151610cfe576000610d01565b60015b60ff1681526020018d60e0015181526020018d61010001518152602001600019815260200160008152602001600181526020018d61014001518152506040518863ffffffff1660e01b8152600401610d5f979695949392919061434a565b606060405180830381865af4158015610d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da091906143fc565b50925090508015610dd6576040840151610dbb600183614137565b81518110610dcb57610dcb6140c1565b602002602001015192505b50915091565b600080600080730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b0316815250886040015189606001518a608001518b60a001518c60c001516040518060e001604052808f6101200151610e72576000610e75565b60015b60ff1681526020018f60e0015181526020018f61010001518152602001600019815260200160008152602001600181526020018f61014001518152506040518863ffffffff1660e01b8152600401610ed3979695949392919061434a565b606060405180830381865af4158015610ef0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1491906143fc565b9250925092506000604051806080016040528060028960e001511480610f3c575060e0890151155b15151515815260200160018960e001511480610f5a575060e0890151155b1515815260e0890180516001908114602084015290511460409091015290508315801590610f86575080515b15610fc557610fbd8787610f9b600188614137565b6000610fa860018a614137565b14610fb4576000610fb7565b60015b8761124f565b610100890152505b8115801590610fd5575060208101515b156110e357865160408801516110df91906000610ff3600187614137565b14610fff576000611002565b60015b81518110611012576110126140c1565b6020026020010151896040015160018661102c9190614137565b8151811061103c5761103c6140c1565b60200260200101518a604001516001876110569190614137565b81518110611066576110666140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611099919061429f565b602060405180830381865afa1580156110b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110da9190614108565b6118af565b5050505b8315611244576040810151156111fd576111038787610f9b600188614137565b610100890152506060810151801561111a57508115155b156111f8576000806111518982611132600188614137565b1461113e576000611141565b60015b61114c600188614137565b611a73565b9150915080156111925761118d8961116a600187614137565b6000611177600189614137565b14611183576000611186565b60015b6001612008565b6111f5565b60608901516111a2600186614137565b815181106111b2576111b26140c1565b60200260200101518211156111f5576111f58960006111d2600188614137565b146111de5760006111e1565b60015b6111ec600188614137565b8560001961212e565b50505b611244565b8115801561120d57508661012001515b801561121d575061010087015115155b80156112365750866101000151670de0b6b3a764000014155b156112445761124487612408565b501595945050505050565b600080856000015161126357856060015192505b855160009061127657866040015161127c565b87602001515b905087604001518681518110611294576112946140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112c7919061429f565b602060405180830381865afa1580156112e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113089190614108565b8411156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906113595760405162461bcd60e51b81526004016104c59190613b3f565b5087604001518681518110611370576113706140c1565b60200260200101516001600160a01b031687602001516001600160a01b0316146040518060400160405280601181526020017054532d323520737761702062792061676760781b815250906113d85760405162461bcd60e51b81526004016104c59190613b3f565b50876060015186815181106113ef576113ef6140c1565b60200260200101518411156118275761142688604001518781518110611417576114176140c1565b602002602001015185836125eb565b600061144e89604001518781518110611441576114416140c1565b602002602001015161265c565b8851909150156114de576114668589606001516126cc565b94506114d68960000151838b604001518a81518110611487576114876140c1565b60200260200101518c604001518a815181106114a5576114a56140c1565b60200260200101518961012c8f606001518e815181106114c7576114c76140c1565b602002602001015160016126e4565b509350611591565b88602001516001600160a01b0316826001600160a01b03161461150457611504826127ef565b600080836001600160a01b03168a60800151604051611523919061442a565b6000604051808303816000865af19150503d8060008114611560576040519150601f19603f3d011682016040523d82523d6000602084013e611565565b606091505b509150915081819061158a5760405162461bcd60e51b81526004016104c59190613b3f565b5086955050505b88600001516001600160a01b031663291f89c48a6040015189815181106115ba576115ba6140c1565b6020026020010151878c604001518a815181106115d9576115d96140c1565b6020026020010151856115fb8f604001518d81518110611441576114416140c1565b6116059190614137565b61012c6040518663ffffffff1660e01b8152600401611628959493929190614446565b602060405180830381865afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611669919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906116b25760405162461bcd60e51b81526004016104c59190613b3f565b507f650da787b25801954b4e03c78b9c6b07fddcbda246347411c49d282c7225f592886060015186836116f48d604001518b81518110611441576114416140c1565b6116fe9190614137565b8c60a001518b81518110611714576117146140c1565b60200260200101518d608001518b81518110611732576117326140c1565b60200260200101518e60a001518c81518110611750576117506140c1565b60200260200101518f608001518e8151811061176e5761176e6140c1565b60200260200101518c6117819190614497565b61178b9190614497565b61179591906144c4565b61179f91906144c4565b868e604001518d815181106117b6576117b66140c1565b60200260200101518f604001518d815181106117d4576117d46140c1565b602090810291909101810151604080519889529188019690965286019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e00160405180910390a1505b8288610120015161183d5788610100015161189f565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190614108565b92509250505b9550959350505050565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118e1919061429f565b602060405180830381865afa1580156118fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119229190614108565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b815260040161195994939291906144d8565b60408051808303816000875af1158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190614502565b5090506119b68187106119ae57816119b0565b865b836126cc565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3c9190614502565b909650905080861115611a5657611a538187614137565b95505b611a638a8a8a87876128ac565b9550505050509450945094915050565b600080611aaf6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8560a001518581518110611ac557611ac56140c1565b602002602001015186608001518681518110611ae357611ae36140c1565b602002602001015187604001518781518110611b0157611b016140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611b34919061429f565b602060405180830381865afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190614108565b611b7f9190614497565b611b8991906144c4565b604082015260a0860151805185908110611ba557611ba56140c1565b602002602001015186608001518581518110611bc357611bc36140c1565b602002602001015187604001518681518110611be157611be16140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611c14919061429f565b602060405180830381865afa158015611c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c559190614108565b611c5f9190614497565b611c6991906144c4565b60608201528415611c7f57856101000151611c97565b610100860151611c9790670de0b6b3a7640000614137565b81528415611cbc57610100860151611cb790670de0b6b3a7640000614137565b611cc3565b8561010001515b602082015260a0860151805186908110611cdf57611cdf6140c1565b602002602001015186608001518581518110611cfd57611cfd6140c1565b60200260200101518760a001518681518110611d1b57611d1b6140c1565b602002602001015188608001518881518110611d3957611d396140c1565b6020026020010151611d4b9190614497565b611d5d90670de0b6b3a7640000614497565b611d6791906144c4565b611d7191906144c4565b81608001818152505060008087600001516001600160a01b031663e4c2be70308a604001518a81518110611da757611da76140c1565b60200260200101518b604001518a81518110611dc557611dc56140c1565b602002602001015160016040518563ffffffff1660e01b8152600401611dee94939291906144d8565b6040805180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614502565b9150915081600003611f0e5760208301518351600091611e4d91614526565b845160608601516040870151611e639190614526565b611e6d9190614497565b611e7791906144c4565b9050836040015181118015611f0657508860a001518881518110611e9d57611e9d6140c1565b602002602001015189608001518981518110611ebb57611ebb6140c1565b60200260200101518a606001518a81518110611ed957611ed96140c1565b6020026020010151611eeb9190614497565b611ef591906144c4565b6040850151611f049083614137565b115b945050611faa565b8260000151670de0b6b3a7640000838386608001518760200151611f329190614497565b611f3c9190614497565b611f4691906144c4565b611f5091906144c4565b611f5a9190614539565b83604001518460200151611f6e9190614497565b60608501518551611f7f9190614497565b611f899190614561565b611f939190614588565b60a0840181905260001215611faa578260a0015194505b87608001518681518110611fc057611fc06140c1565b60200260200101518860a001518781518110611fde57611fde6140c1565b602002602001015186611ff19190614497565b611ffb91906144c4565b9450505050935093915050565b61212884848487604001518781518110612024576120246140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612057919061429f565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614108565b886040015187815181106120ae576120ae6140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120e1919061429f565b602060405180830381865afa1580156120fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121229190614108565b86612a95565b50505050565b600085604001518481518110612146576121466140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612179919061429f565b602060405180830381865afa158015612196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ba9190614108565b90506122068660000151876040015187815181106121da576121da6140c1565b6020026020010151886040015187815181106121f8576121f86140c1565b6020026020010151866118af565b505050600086604001518581518110612221576122216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612254919061429f565b602060405180830381865afa158015612271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122959190614108565b905060008183116122a75760006122b1565b6122b18284614137565b905084811080156122e95750876060015186815181106122d3576122d36140c1565b602002602001015181866122e79190614137565b115b156123fe57600088600001516001600160a01b031663e4c2be70308b604001518b8151811061231a5761231a6140c1565b60200260200101518c604001518b81518110612338576123386140c1565b602002602001015160016040518563ffffffff1660e01b815260040161236194939291906144d8565b6040805180830381865afa15801561237d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a19190614502565b509050886060015187815181106123ba576123ba6140c1565b6020026020010151811180156123cf57508481105b156123ef576123ea8989896123e4868b614137565b8561212e565b6123fc565b6123fc89888a6000612008565b505b5050505050505050565b60008160400151600081518110612421576124216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612454919061429f565b602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614108565b9050600082604001516001815181106124b0576124b06140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016124e3919061429f565b602060405180830381865afa158015612500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125249190614108565b905060008061254785608001518660a00151868689610100015160006001612db8565b915091508184111561259a57846060015160008151811061256a5761256a6140c1565b6020026020010151828561257e9190614137565b111561259557612595856000600187876001612a95565b6125e4565b808311156125e45784606001516000815181106125b9576125b96140c1565b602002602001015181846125cd9190614137565b11156125e4576125e4856001600086886001612a95565b5050505050565b60405163095ea7b360e01b81526001600160a01b0384169063095ea7b3906126199084908690600401613ed7565b6020604051808303816000875af1158015612638573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061447a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061268b90309060040161429f565b602060405180830381865afa1580156126a8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614108565b60008183106126db57816126dd565b825b9392505050565b6000808386116126f9575060009050806127e2565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa15801561274b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261277391908101906145fb565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506127ca5760405162461bcd60e51b81526004016104c59190613b3f565b50866127dc8c838d8d8d8d8d8c612f47565b92509250505b9850989650505050505050565b6001600160a01b038116731111111254eeb25477b68fb85ed929f73a960582148061283657506001600160a01b038116736352a56caadc4f1e25cd6c75970fa768a3304e64145b8061285d57506001600160a01b038116736dd434082eab5cd134b33719ec1ff05fe985b97b145b604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b815250906128a85760405162461bcd60e51b81526004016104c59190613b3f565b5050565b600080606484106118a5576128cb6001600160a01b0386168886613225565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561292c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129509190614714565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906129e590309060040161429f565b602060405180830381865afa158015612a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a269190614108565b9050808511612a36576000612a40565b612a408186614137565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b60208201529093508215612a885760405162461bcd60e51b81526004016104c59190613b3f565b5050509550959350505050565b8015612bac57600086600001516001600160a01b031663e4c2be703089604001518881518110612ac757612ac76140c1565b60200260200101518a604001518a81518110612ae557612ae56140c1565b602002602001015160006040518563ffffffff1660e01b8152600401612b0e94939291906144d8565b6040805180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614502565b509050606481106040518060400160405280601a81526020017f54532d3239206f70706f7369746520646562742065786973747300000000000081525090612ba95760405162461bcd60e51b81526004016104c59190613b3f565b50505b600060405180610160016040528060405180604001604052808a600001516001600160a01b031681526020018a602001516001600160a01b0316815250815260200188604001518881518110612c0457612c046140c1565b60200260200101516001600160a01b0316815260200188604001518781518110612c3057612c306140c1565b60200260200101516001600160a01b0316815260200160008814612c5957886101000151612c71565b610100890151612c7190670de0b6b3a7640000614137565b81526020018715612c9957610100890151612c9490670de0b6b3a7640000614137565b612ca0565b8861010001515b81526020018860a001518781518110612cbb57612cbb6140c1565b602002602001015189608001518981518110612cd957612cd96140c1565b60200260200101518a60a001518a81518110612cf757612cf76140c1565b60200260200101518b608001518a81518110612d1557612d156140c1565b6020026020010151670de0b6b3a7640000612d309190614497565b612d3a9190614497565b612d4491906144c4565b612d4e91906144c4565b815260200188606001518881518110612d6957612d696140c1565b6020026020010151815260200160008152602001600081526020018781526020018681525090506123fc8160405180604001604052808a6080015181526020018a60a001518152508686613280565b6000806000888581518110612dcf57612dcf6140c1565b60200260200101518a8681518110612de957612de96140c1565b602002602001015189612dfc9190614497565b612e0691906144c4565b90506000898581518110612e1c57612e1c6140c1565b60200260200101518b8681518110612e3657612e366140c1565b602002602001015189612e499190614497565b612e5391906144c4565b90508615612e8857670de0b6b3a764000087612e6f8385614526565b612e799190614497565b612e8391906144c4565b612e8b565b60005b92508a8681518110612e9f57612e9f6140c1565b60200260200101518a8781518110612eb957612eb96140c1565b6020026020010151848385612ece9190614526565b612ed89190614137565b612ee29190614497565b612eec91906144c4565b93508a8581518110612f0057612f006140c1565b60200260200101518a8681518110612f1a57612f1a6140c1565b602002602001015184612f2d9190614497565b612f3791906144c4565b9250505097509795505050505050565b6000612f548685896133ed565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612f8390309060040161429f565b602060405180830381865afa158015612fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc49190614108565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890612ff7908c908990899060040161474a565b600060405180830381600087803b15801561301157600080fd5b505af1158015613025573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a082319061305890309060040161429f565b602060405180830381865afa158015613075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130999190614108565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906130eb5760405162461bcd60e51b81526004016104c59190613b3f565b506130f68282614137565b925083806131745750604051630a47e27160e21b81526001600160a01b038c169063291f89c490613133908b908a908c9089908c90600401614446565b602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613174919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906131bd5760405162461bcd60e51b81526004016104c59190613b3f565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b61327b8363a9059cbb60e01b8484604051602401613244929190613ed7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613498565b505050565b6000808560e00151600014806132995750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906132e35760405162461bcd60e51b81526004016104c59190613b3f565b506101008601511561335e57856101000151831061331f576133168685886101000151866133119190614137565b61356a565b915091506133e4565b600061333d878787878b61010001516133389190614137565b613703565b5090506133548761334e8388614137565b8661356a565b92509250506133e4565b60e0860151156133d9578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906133be5760405162461bcd60e51b81526004016104c59190613b3f565b50613316868760e00151866133d39190614137565b8561356a565b61331686858561356a565b94509492505050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561343c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134609190614108565b101561327b5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390612619908490600160ff1b90600401613ed7565b60006134ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661390c9092919063ffffffff16565b80519091501561327b578080602001905181019061350b919061447a565b61327b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104c5565b60608381015160808086015160408051600160208201528082019490945283850191909152805180840390940184529101905260009081908190841561363a57670de0b6b3a7640000876080015188606001518960a00151886135cd9190614497565b6135d79190614497565b6135e191906144c4565b6135eb91906144c4565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b815250906136385760405162461bcd60e51b81526004016104c59190613b3f565b505b60208701516136559061364d8489614137565b8951516133ed565b730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab163ca27d10d886000015160000151838a602001518b60400151878c61368f9190614137565b8d60c001516040518763ffffffff1660e01b81526004016136b5969594939291906147cc565b6040805180830381865af41580156136d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f59190614502565b935093505050935093915050565b6000806000856020015187610140015181518110613723576137236140c1565b6020026020010151866000015188610120015181518110613746576137466140c1565b6020026020010151876020015189610120015181518110613769576137696140c1565b602002602001015188600001518a61014001518151811061378c5761378c6140c1565b60200260200101518761379f9190614497565b6137a99190614497565b6137b391906144c4565b6137bd91906144c4565b9050620186a06137cf61012c82614526565b6137d99083614497565b6137e391906144c4565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906138365760405162461bcd60e51b81526004016104c59190613b3f565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e4820152730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab190637de8f56990610104016040805180830381865af41580156138da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fe9190614502565b909890975095505050505050565b606061391b8484600085613923565b949350505050565b6060824710156139845760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104c5565b600080866001600160a01b031685876040516139a0919061442a565b60006040518083038185875af1925050503d80600081146139dd576040519150601f19603f3d011682016040523d82523d6000602084013e6139e2565b606091505b50915091506139f3878383876139fe565b979650505050505050565b60608315613a6d578251600003613a66576001600160a01b0385163b613a665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104c5565b508161391b565b61391b8383815115613a825781518083602001fd5b8060405162461bcd60e51b81526004016104c59190613b3f565b8260048101928215613aca579160200282015b82811115613aca578251825591602001919060010190613aaf565b50613ad6929150613ada565b5090565b5b80821115613ad65760008155600101613adb565b60005b83811015613b0a578181015183820152602001613af2565b50506000910152565b60008151808452613b2b816020860160208601613aef565b601f01601f19169290920160200192915050565b6020815260006126dd6020830184613b13565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613b8a57613b8a613b52565b60405290565b604080519081016001600160401b0381118282101715613b8a57613b8a613b52565b604051601f8201601f191681016001600160401b0381118282101715613bda57613bda613b52565b604052919050565b60008060a08385031215613bf557600080fd5b82359150602084603f850112613c0a57600080fd5b604051608081018181106001600160401b0382111715613c2c57613c2c613b52565b6040528060a0860187811115613c4157600080fd5b8387015b81811015613c5c5780358352918401918401613c45565b50505080925050509250929050565b6001600160a01b0381168114613c8057600080fd5b50565b8035613c8e81613c6b565b919050565b600082601f830112613ca457600080fd5b613cac613b90565b806040840185811115613cbe57600080fd5b845b81811015613ce1578035613cd381613c6b565b845260209384019301613cc0565b509095945050505050565b60006001600160401b03821115613d0557613d05613b52565b5060051b60200190565b600082601f830112613d2057600080fd5b81356020613d35613d3083613cec565b613bb2565b82815260059290921b84018101918181019086841115613d5457600080fd5b8286015b84811015613d78578035613d6b81613c6b565b8352918301918301613d58565b509695505050505050565b600082601f830112613d9457600080fd5b81356020613da4613d3083613cec565b82815260059290921b84018101918181019086841115613dc357600080fd5b8286015b84811015613d785780358352918301918301613dc7565b600082601f830112613def57600080fd5b613df7613b90565b806040840185811115613e0957600080fd5b845b81811015613ce1578035845260209384019301613e0b565b6000806000806000806101008789031215613e3d57600080fd5b613e478888613c93565b955060408701356001600160401b0380821115613e6357600080fd5b613e6f8a838b01613d0f565b96506060890135915080821115613e8557600080fd5b613e918a838b01613d83565b95506080890135915080821115613ea757600080fd5b50613eb489828a01613d83565b93505060a08701359150613ecb8860c08901613dde565b90509295509295509295565b6001600160a01b03929092168252602082015260400190565b600060208284031215613f0257600080fd5b5035919050565b60008060408385031215613f1c57600080fd5b82359150602083013560048110613f3257600080fd5b809150509250929050565b60006001600160401b03821115613f5657613f56613b52565b50601f01601f191660200190565b600082601f830112613f7557600080fd5b8135613f83613d3082613f3d565b818152846020838601011115613f9857600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114613c8057600080fd5b8035613c8e81613fb5565b6000806000806000806000806000806101808b8d031215613fee57600080fd5b613ff88c8c613c93565b995060408b01356001600160401b038082111561401457600080fd5b6140208e838f01613d0f565b9a5060608d013591508082111561403657600080fd5b6140428e838f01613d83565b995061405060808e01613c83565b985060a08d0135975061406560c08e01613c83565b965060e08d013591508082111561407b57600080fd5b506140888d828e01613f64565b9450506140986101008c01613fc3565b92506101208b013591506140b08c6101408d01613dde565b90509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b60808101818360005b60048110156140ff5781518352602092830192909101906001016140e0565b50505092915050565b60006020828403121561411a57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077f5761077f614121565b600181815b8085111561418557816000190482111561416b5761416b614121565b8085161561417857918102915b93841c939080029061414f565b509250929050565b60008261419c5750600161077f565b816141a95750600061077f565b81600181146141bf57600281146141c9576141e5565b600191505061077f565b60ff8411156141da576141da614121565b50506001821b61077f565b5060208310610133831016604e8410600b8410161715614208575081810a61077f565b614212838361414a565b806000190482111561422657614226614121565b029392505050565b60006126dd838361418d565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561426257600080fd5b81516126dd81613c6b565b60006020828403121561427f57600080fd5b815160ff811681146126dd57600080fd5b60006126dd60ff84168361418d565b6001600160a01b0391909116815260200190565b600081518084526020808501945080840160005b838110156142ec5781516001600160a01b0316875295820195908201906001016142c7565b509495945050505050565b600081518084526020808501945080840160005b838110156142ec5781518752958201959082019060010161430b565b8060005b600781101561212857815184526020938401939091019060010161432b565b60006101c0828a835b600281101561437b5781516001600160a01b0316835260209283019290910190600101614353565b5050508060408401526143908184018a6142b3565b905082810360608401526143a481896142f7565b905082810360808401526143b881886142f7565b905082810360a08401526143cc81876142f7565b905082810360c08401526143e081866142f7565b9150506143f060e0830184614327565b98975050505050505050565b60008060006060848603121561441157600080fd5b8351925060208401519150604084015190509250925092565b6000825161443c818460208701613aef565b9190910192915050565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b60006020828403121561448c57600080fd5b81516126dd81613fb5565b808202811582820484141761077f5761077f614121565b634e487b7160e01b600052601260045260246000fd5b6000826144d3576144d36144ae565b500490565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561451557600080fd5b505080516020909101519092909150565b8082018082111561077f5761077f614121565b808201828112600083128015821682158216171561455957614559614121565b505092915050565b818103600083128015838313168383128216171561458157614581614121565b5092915050565b600082614597576145976144ae565b600160ff1b8214600019841416156145b1576145b1614121565b500590565b600082601f8301126145c757600080fd5b81516145d5613d3082613f3d565b8181528460208386010111156145ea57600080fd5b61391b826020830160208701613aef565b600080604080848603121561460f57600080fd5b83516001600160401b038082111561462657600080fd5b818601915086601f83011261463a57600080fd5b8151602061464a613d3083613cec565b82815260079290921b8401810191818101908a84111561466957600080fd5b948201945b838610156146e3576080868c0312156146875760008081fd5b61468f613b68565b865161469a81613c6b565b8152868401516146a981613c6b565b81850152868801516146ba81613c6b565b818901526060878101516146cd81613c6b565b908201528252608095909501949082019061466e565b918901519197509094505050808311156146fc57600080fd5b505061470a858286016145b6565b9150509250929050565b6000806000806080858703121561472a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6060808252845182820181905260009190608090818501906020808a01865b838110156147b157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614769565b50508601979097526040909401949094525090949350505050565b600060018060a01b03808916835260c060208401526147ee60c0840189613b13565b9681166040840152949094166060820152608081019290925260a090910152509291505056fe5042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a2646970667358221220c8a99e8b5addb5b446bc3b4ddddfcec75611a6c57eb3f5a39866806e9265f0cd64736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106102475760003560e01c8063767e17e811610145578063c143e087116100c2578063d7a1d53511610086578063d7a1d535146102e8578063e0c24b3a1461042e578063e642319514610436578063ec88f9ff146102a2578063f7ebc365146102a257600080fd5b8063c143e08714610313578063c63891c7146102a2578063c8ce726c146102e0578063cdb549351461041e578063d3a9335c1461042657600080fd5b8063a200f62b11610109578063a200f62b146102e0578063a7231ef6146103da578063aea02d91146103e2578063c00d3e0b146102e8578063c06ab65f146103ea57600080fd5b8063767e17e8146102e0578063831fd9ea146103135780638f875cc814610313578063927154f0146103a75780639c2d8d63146102e857600080fd5b806337d11dc1116101d357806360339c591161019757806360339c59146102e8578063603938b814610313578063673d63db1461031b5780636bffb346146103575780637545be261461037757600080fd5b806337d11dc1146102e857806343fc304a146102f057806346326a29146102f8578063556ce728146103005780635be05524146102e057600080fd5b8063137c52b21161021a578063137c52b2146102a25780631429888b146102aa57806314ad109e146102b2578063217052d1146102a257806335f33bc2146102e057600080fd5b8063058ba3db1461024c5780630593c4c91461026a5780631033193e1461028c5780631200fb3c146102a2575b600080fd5b61025461043e565b6040516102619190613b3f565b60405180910390f35b81801561027657600080fd5b5061028a610285366004613be2565b61045a565b005b610294600981565b604051908152602001610261565b610294600181565b610294600781565b8180156102be57600080fd5b506102d26102cd366004613e23565b6105f6565b604051610261929190613ed7565b610294600281565b610294600081565b610294600c81565b610294600a81565b61029461030e366004613ef0565b610758565b610294600381565b6102546040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525081565b81801561036357600080fd5b5061028a610372366004613f09565b610785565b81801561038357600080fd5b50610397610392366004613fce565b6107e9565b6040519015158152602001610261565b610254604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b81525081565b610294600b81565b610294600581565b61025460405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525081565b610294606481565b610294600481565b610294600681565b610294600881565b6040518060600160405280602281526020016148156022913981565b805115801561046b57506020810151155b8061047b57506020810151815111155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906104ce5760405162461bcd60e51b81526004016104c59190613b3f565b60405180910390fd5b5060408101511580156104e357506060810151155b806104f657506060810151604082015110155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906105405760405162461bcd60e51b81526004016104c59190613b3f565b508051158015906105545750604081015115155b156105ab5780516040808301518151808301909252601382527254532d333020696e76616c69642076616c756560681b60208301529091106105a95760405162461bcd60e51b81526004016104c59190613b3f565b505b6105ba60018301826004613a9c565b507fef6880b7ef7308e1a0fdc54890042b9fc1d2355795cd67a12c76d38438e643b5816040516105ea91906140d7565b60405180910390a15050565b600080808061061661060e8b835b60200201516109b6565b8a6002610a7b565b9150915060006040518061016001604052808c60006002811061063b5761063b6140c1565b60200201516001600160a01b031681526020018c600160028110610661576106616140c1565b60200201516001600160a01b031681526020018b81526020018a8152602001848152602001838152602001898152602001888152602001600019886000600281106106ae576106ae6140c1565b6020020151146106bf578751610721565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107219190614108565b8152875160001914602082015260400187600160200201519052905061074681610c69565b94509450505050965096945050505050565b60006012821061076957600161077f565b610774826012614137565b61077f90600a61422e565b92915050565b81548190839060ff191660018360038111156107a3576107a361423a565b02179055507f5a7ee3c5ef7f4e3625ee638c3a95481dc4cbfaceda022d1e8fba8ed7fa2208e18160038111156107db576107db61423a565b6040519081526020016105ea565b600080806108026107fa8e83610604565b8d6002610a7b565b9150915060006040518061016001604052808f600060028110610827576108276140c1565b60200201516001600160a01b031681526020018f60016002811061084d5761084d6140c1565b60200201516001600160a01b031681526020018e81526020018d815260200184815260200183815260200160026001600160401b0381111561089157610891613b52565b6040519080825280602002602001820160405280156108ba578160200160208202803683370190505b508152602081018890528651604090910190600019146108db57865161093d565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093d9190614108565b815286516000191460208201526040018660016020020151815250905060006040518060a0016040528089151581526020018d6001600160a01b031681526020018b6001600160a01b031681526020018c81526020018a81525090506109a38282610ddc565b9f9e505050505050505050505050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1a9190614250565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a57573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614250565b606080826001600160401b03811115610a9657610a96613b52565b604051908082528060200260200182016040528015610abf578160200160208202803683370190505b509150826001600160401b03811115610ada57610ada613b52565b604051908082528060200260200182016040528015610b03578160200160208202803683370190505b50905060005b83811015610c6057848181518110610b2357610b236140c1565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c919061426d565b610b9790600a614290565b828281518110610ba957610ba96140c1565b602002602001018181525050856001600160a01b031663b3596f07868381518110610bd657610bd66140c1565b60200260200101516040518263ffffffff1660e01b8152600401610bfa919061429f565b602060405180830381865afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3b9190614108565b838281518110610c4d57610c4d6140c1565b6020908102919091010152600101610b09565b50935093915050565b600080600073__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528087600001516001600160a01b03166001600160a01b0316815260200187602001516001600160a01b03166001600160a01b03168152508660400151876060015188608001518960a001518a60c001516040518060e001604052808d6101200151610cfe576000610d01565b60015b60ff1681526020018d60e0015181526020018d61010001518152602001600019815260200160008152602001600181526020018d61014001518152506040518863ffffffff1660e01b8152600401610d5f979695949392919061434a565b606060405180830381865af4158015610d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da091906143fc565b50925090508015610dd6576040840151610dbb600183614137565b81518110610dcb57610dcb6140c1565b602002602001015192505b50915091565b60008060008073__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b0316815250886040015189606001518a608001518b60a001518c60c001516040518060e001604052808f6101200151610e72576000610e75565b60015b60ff1681526020018f60e0015181526020018f61010001518152602001600019815260200160008152602001600181526020018f61014001518152506040518863ffffffff1660e01b8152600401610ed3979695949392919061434a565b606060405180830381865af4158015610ef0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1491906143fc565b9250925092506000604051806080016040528060028960e001511480610f3c575060e0890151155b15151515815260200160018960e001511480610f5a575060e0890151155b1515815260e0890180516001908114602084015290511460409091015290508315801590610f86575080515b15610fc557610fbd8787610f9b600188614137565b6000610fa860018a614137565b14610fb4576000610fb7565b60015b8761124f565b610100890152505b8115801590610fd5575060208101515b156110e357865160408801516110df91906000610ff3600187614137565b14610fff576000611002565b60015b81518110611012576110126140c1565b6020026020010151896040015160018661102c9190614137565b8151811061103c5761103c6140c1565b60200260200101518a604001516001876110569190614137565b81518110611066576110666140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611099919061429f565b602060405180830381865afa1580156110b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110da9190614108565b6118af565b5050505b8315611244576040810151156111fd576111038787610f9b600188614137565b610100890152506060810151801561111a57508115155b156111f8576000806111518982611132600188614137565b1461113e576000611141565b60015b61114c600188614137565b611a73565b9150915080156111925761118d8961116a600187614137565b6000611177600189614137565b14611183576000611186565b60015b6001612008565b6111f5565b60608901516111a2600186614137565b815181106111b2576111b26140c1565b60200260200101518211156111f5576111f58960006111d2600188614137565b146111de5760006111e1565b60015b6111ec600188614137565b8560001961212e565b50505b611244565b8115801561120d57508661012001515b801561121d575061010087015115155b80156112365750866101000151670de0b6b3a764000014155b156112445761124487612408565b501595945050505050565b600080856000015161126357856060015192505b855160009061127657866040015161127c565b87602001515b905087604001518681518110611294576112946140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112c7919061429f565b602060405180830381865afa1580156112e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113089190614108565b8411156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906113595760405162461bcd60e51b81526004016104c59190613b3f565b5087604001518681518110611370576113706140c1565b60200260200101516001600160a01b031687602001516001600160a01b0316146040518060400160405280601181526020017054532d323520737761702062792061676760781b815250906113d85760405162461bcd60e51b81526004016104c59190613b3f565b50876060015186815181106113ef576113ef6140c1565b60200260200101518411156118275761142688604001518781518110611417576114176140c1565b602002602001015185836125eb565b600061144e89604001518781518110611441576114416140c1565b602002602001015161265c565b8851909150156114de576114668589606001516126cc565b94506114d68960000151838b604001518a81518110611487576114876140c1565b60200260200101518c604001518a815181106114a5576114a56140c1565b60200260200101518961012c8f606001518e815181106114c7576114c76140c1565b602002602001015160016126e4565b509350611591565b88602001516001600160a01b0316826001600160a01b03161461150457611504826127ef565b600080836001600160a01b03168a60800151604051611523919061442a565b6000604051808303816000865af19150503d8060008114611560576040519150601f19603f3d011682016040523d82523d6000602084013e611565565b606091505b509150915081819061158a5760405162461bcd60e51b81526004016104c59190613b3f565b5086955050505b88600001516001600160a01b031663291f89c48a6040015189815181106115ba576115ba6140c1565b6020026020010151878c604001518a815181106115d9576115d96140c1565b6020026020010151856115fb8f604001518d81518110611441576114416140c1565b6116059190614137565b61012c6040518663ffffffff1660e01b8152600401611628959493929190614446565b602060405180830381865afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611669919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906116b25760405162461bcd60e51b81526004016104c59190613b3f565b507f650da787b25801954b4e03c78b9c6b07fddcbda246347411c49d282c7225f592886060015186836116f48d604001518b81518110611441576114416140c1565b6116fe9190614137565b8c60a001518b81518110611714576117146140c1565b60200260200101518d608001518b81518110611732576117326140c1565b60200260200101518e60a001518c81518110611750576117506140c1565b60200260200101518f608001518e8151811061176e5761176e6140c1565b60200260200101518c6117819190614497565b61178b9190614497565b61179591906144c4565b61179f91906144c4565b868e604001518d815181106117b6576117b66140c1565b60200260200101518f604001518d815181106117d4576117d46140c1565b602090810291909101810151604080519889529188019690965286019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e00160405180910390a1505b8288610120015161183d5788610100015161189f565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190614108565b92509250505b9550959350505050565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118e1919061429f565b602060405180830381865afa1580156118fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119229190614108565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b815260040161195994939291906144d8565b60408051808303816000875af1158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190614502565b5090506119b68187106119ae57816119b0565b865b836126cc565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3c9190614502565b909650905080861115611a5657611a538187614137565b95505b611a638a8a8a87876128ac565b9550505050509450945094915050565b600080611aaf6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8560a001518581518110611ac557611ac56140c1565b602002602001015186608001518681518110611ae357611ae36140c1565b602002602001015187604001518781518110611b0157611b016140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611b34919061429f565b602060405180830381865afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190614108565b611b7f9190614497565b611b8991906144c4565b604082015260a0860151805185908110611ba557611ba56140c1565b602002602001015186608001518581518110611bc357611bc36140c1565b602002602001015187604001518681518110611be157611be16140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611c14919061429f565b602060405180830381865afa158015611c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c559190614108565b611c5f9190614497565b611c6991906144c4565b60608201528415611c7f57856101000151611c97565b610100860151611c9790670de0b6b3a7640000614137565b81528415611cbc57610100860151611cb790670de0b6b3a7640000614137565b611cc3565b8561010001515b602082015260a0860151805186908110611cdf57611cdf6140c1565b602002602001015186608001518581518110611cfd57611cfd6140c1565b60200260200101518760a001518681518110611d1b57611d1b6140c1565b602002602001015188608001518881518110611d3957611d396140c1565b6020026020010151611d4b9190614497565b611d5d90670de0b6b3a7640000614497565b611d6791906144c4565b611d7191906144c4565b81608001818152505060008087600001516001600160a01b031663e4c2be70308a604001518a81518110611da757611da76140c1565b60200260200101518b604001518a81518110611dc557611dc56140c1565b602002602001015160016040518563ffffffff1660e01b8152600401611dee94939291906144d8565b6040805180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614502565b9150915081600003611f0e5760208301518351600091611e4d91614526565b845160608601516040870151611e639190614526565b611e6d9190614497565b611e7791906144c4565b9050836040015181118015611f0657508860a001518881518110611e9d57611e9d6140c1565b602002602001015189608001518981518110611ebb57611ebb6140c1565b60200260200101518a606001518a81518110611ed957611ed96140c1565b6020026020010151611eeb9190614497565b611ef591906144c4565b6040850151611f049083614137565b115b945050611faa565b8260000151670de0b6b3a7640000838386608001518760200151611f329190614497565b611f3c9190614497565b611f4691906144c4565b611f5091906144c4565b611f5a9190614539565b83604001518460200151611f6e9190614497565b60608501518551611f7f9190614497565b611f899190614561565b611f939190614588565b60a0840181905260001215611faa578260a0015194505b87608001518681518110611fc057611fc06140c1565b60200260200101518860a001518781518110611fde57611fde6140c1565b602002602001015186611ff19190614497565b611ffb91906144c4565b9450505050935093915050565b61212884848487604001518781518110612024576120246140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612057919061429f565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614108565b886040015187815181106120ae576120ae6140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120e1919061429f565b602060405180830381865afa1580156120fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121229190614108565b86612a95565b50505050565b600085604001518481518110612146576121466140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612179919061429f565b602060405180830381865afa158015612196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ba9190614108565b90506122068660000151876040015187815181106121da576121da6140c1565b6020026020010151886040015187815181106121f8576121f86140c1565b6020026020010151866118af565b505050600086604001518581518110612221576122216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612254919061429f565b602060405180830381865afa158015612271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122959190614108565b905060008183116122a75760006122b1565b6122b18284614137565b905084811080156122e95750876060015186815181106122d3576122d36140c1565b602002602001015181866122e79190614137565b115b156123fe57600088600001516001600160a01b031663e4c2be70308b604001518b8151811061231a5761231a6140c1565b60200260200101518c604001518b81518110612338576123386140c1565b602002602001015160016040518563ffffffff1660e01b815260040161236194939291906144d8565b6040805180830381865afa15801561237d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a19190614502565b509050886060015187815181106123ba576123ba6140c1565b6020026020010151811180156123cf57508481105b156123ef576123ea8989896123e4868b614137565b8561212e565b6123fc565b6123fc89888a6000612008565b505b5050505050505050565b60008160400151600081518110612421576124216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612454919061429f565b602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614108565b9050600082604001516001815181106124b0576124b06140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016124e3919061429f565b602060405180830381865afa158015612500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125249190614108565b905060008061254785608001518660a00151868689610100015160006001612db8565b915091508184111561259a57846060015160008151811061256a5761256a6140c1565b6020026020010151828561257e9190614137565b111561259557612595856000600187876001612a95565b6125e4565b808311156125e45784606001516000815181106125b9576125b96140c1565b602002602001015181846125cd9190614137565b11156125e4576125e4856001600086886001612a95565b5050505050565b60405163095ea7b360e01b81526001600160a01b0384169063095ea7b3906126199084908690600401613ed7565b6020604051808303816000875af1158015612638573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061447a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061268b90309060040161429f565b602060405180830381865afa1580156126a8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614108565b60008183106126db57816126dd565b825b9392505050565b6000808386116126f9575060009050806127e2565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa15801561274b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261277391908101906145fb565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506127ca5760405162461bcd60e51b81526004016104c59190613b3f565b50866127dc8c838d8d8d8d8d8c612f47565b92509250505b9850989650505050505050565b6001600160a01b038116731111111254eeb25477b68fb85ed929f73a960582148061283657506001600160a01b038116736352a56caadc4f1e25cd6c75970fa768a3304e64145b8061285d57506001600160a01b038116736dd434082eab5cd134b33719ec1ff05fe985b97b145b604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b815250906128a85760405162461bcd60e51b81526004016104c59190613b3f565b5050565b600080606484106118a5576128cb6001600160a01b0386168886613225565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561292c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129509190614714565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906129e590309060040161429f565b602060405180830381865afa158015612a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a269190614108565b9050808511612a36576000612a40565b612a408186614137565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b60208201529093508215612a885760405162461bcd60e51b81526004016104c59190613b3f565b5050509550959350505050565b8015612bac57600086600001516001600160a01b031663e4c2be703089604001518881518110612ac757612ac76140c1565b60200260200101518a604001518a81518110612ae557612ae56140c1565b602002602001015160006040518563ffffffff1660e01b8152600401612b0e94939291906144d8565b6040805180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614502565b509050606481106040518060400160405280601a81526020017f54532d3239206f70706f7369746520646562742065786973747300000000000081525090612ba95760405162461bcd60e51b81526004016104c59190613b3f565b50505b600060405180610160016040528060405180604001604052808a600001516001600160a01b031681526020018a602001516001600160a01b0316815250815260200188604001518881518110612c0457612c046140c1565b60200260200101516001600160a01b0316815260200188604001518781518110612c3057612c306140c1565b60200260200101516001600160a01b0316815260200160008814612c5957886101000151612c71565b610100890151612c7190670de0b6b3a7640000614137565b81526020018715612c9957610100890151612c9490670de0b6b3a7640000614137565b612ca0565b8861010001515b81526020018860a001518781518110612cbb57612cbb6140c1565b602002602001015189608001518981518110612cd957612cd96140c1565b60200260200101518a60a001518a81518110612cf757612cf76140c1565b60200260200101518b608001518a81518110612d1557612d156140c1565b6020026020010151670de0b6b3a7640000612d309190614497565b612d3a9190614497565b612d4491906144c4565b612d4e91906144c4565b815260200188606001518881518110612d6957612d696140c1565b6020026020010151815260200160008152602001600081526020018781526020018681525090506123fc8160405180604001604052808a6080015181526020018a60a001518152508686613280565b6000806000888581518110612dcf57612dcf6140c1565b60200260200101518a8681518110612de957612de96140c1565b602002602001015189612dfc9190614497565b612e0691906144c4565b90506000898581518110612e1c57612e1c6140c1565b60200260200101518b8681518110612e3657612e366140c1565b602002602001015189612e499190614497565b612e5391906144c4565b90508615612e8857670de0b6b3a764000087612e6f8385614526565b612e799190614497565b612e8391906144c4565b612e8b565b60005b92508a8681518110612e9f57612e9f6140c1565b60200260200101518a8781518110612eb957612eb96140c1565b6020026020010151848385612ece9190614526565b612ed89190614137565b612ee29190614497565b612eec91906144c4565b93508a8581518110612f0057612f006140c1565b60200260200101518a8681518110612f1a57612f1a6140c1565b602002602001015184612f2d9190614497565b612f3791906144c4565b9250505097509795505050505050565b6000612f548685896133ed565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612f8390309060040161429f565b602060405180830381865afa158015612fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc49190614108565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890612ff7908c908990899060040161474a565b600060405180830381600087803b15801561301157600080fd5b505af1158015613025573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a082319061305890309060040161429f565b602060405180830381865afa158015613075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130999190614108565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906130eb5760405162461bcd60e51b81526004016104c59190613b3f565b506130f68282614137565b925083806131745750604051630a47e27160e21b81526001600160a01b038c169063291f89c490613133908b908a908c9089908c90600401614446565b602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613174919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906131bd5760405162461bcd60e51b81526004016104c59190613b3f565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b61327b8363a9059cbb60e01b8484604051602401613244929190613ed7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613498565b505050565b6000808560e00151600014806132995750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906132e35760405162461bcd60e51b81526004016104c59190613b3f565b506101008601511561335e57856101000151831061331f576133168685886101000151866133119190614137565b61356a565b915091506133e4565b600061333d878787878b61010001516133389190614137565b613703565b5090506133548761334e8388614137565b8661356a565b92509250506133e4565b60e0860151156133d9578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906133be5760405162461bcd60e51b81526004016104c59190613b3f565b50613316868760e00151866133d39190614137565b8561356a565b61331686858561356a565b94509492505050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561343c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134609190614108565b101561327b5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390612619908490600160ff1b90600401613ed7565b60006134ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661390c9092919063ffffffff16565b80519091501561327b578080602001905181019061350b919061447a565b61327b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104c5565b60608381015160808086015160408051600160208201528082019490945283850191909152805180840390940184529101905260009081908190841561363a57670de0b6b3a7640000876080015188606001518960a00151886135cd9190614497565b6135d79190614497565b6135e191906144c4565b6135eb91906144c4565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b815250906136385760405162461bcd60e51b81526004016104c59190613b3f565b505b60208701516136559061364d8489614137565b8951516133ed565b73__$e930d50fb5f4f1298547dbcb2bb0591990$__63ca27d10d886000015160000151838a602001518b60400151878c61368f9190614137565b8d60c001516040518763ffffffff1660e01b81526004016136b5969594939291906147cc565b6040805180830381865af41580156136d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f59190614502565b935093505050935093915050565b6000806000856020015187610140015181518110613723576137236140c1565b6020026020010151866000015188610120015181518110613746576137466140c1565b6020026020010151876020015189610120015181518110613769576137696140c1565b602002602001015188600001518a61014001518151811061378c5761378c6140c1565b60200260200101518761379f9190614497565b6137a99190614497565b6137b391906144c4565b6137bd91906144c4565b9050620186a06137cf61012c82614526565b6137d99083614497565b6137e391906144c4565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906138365760405162461bcd60e51b81526004016104c59190613b3f565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e482015273__$e930d50fb5f4f1298547dbcb2bb0591990$__90637de8f56990610104016040805180830381865af41580156138da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fe9190614502565b909890975095505050505050565b606061391b8484600085613923565b949350505050565b6060824710156139845760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104c5565b600080866001600160a01b031685876040516139a0919061442a565b60006040518083038185875af1925050503d80600081146139dd576040519150601f19603f3d011682016040523d82523d6000602084013e6139e2565b606091505b50915091506139f3878383876139fe565b979650505050505050565b60608315613a6d578251600003613a66576001600160a01b0385163b613a665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104c5565b508161391b565b61391b8383815115613a825781518083602001fd5b8060405162461bcd60e51b81526004016104c59190613b3f565b8260048101928215613aca579160200282015b82811115613aca578251825591602001919060010190613aaf565b50613ad6929150613ada565b5090565b5b80821115613ad65760008155600101613adb565b60005b83811015613b0a578181015183820152602001613af2565b50506000910152565b60008151808452613b2b816020860160208601613aef565b601f01601f19169290920160200192915050565b6020815260006126dd6020830184613b13565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613b8a57613b8a613b52565b60405290565b604080519081016001600160401b0381118282101715613b8a57613b8a613b52565b604051601f8201601f191681016001600160401b0381118282101715613bda57613bda613b52565b604052919050565b60008060a08385031215613bf557600080fd5b82359150602084603f850112613c0a57600080fd5b604051608081018181106001600160401b0382111715613c2c57613c2c613b52565b6040528060a0860187811115613c4157600080fd5b8387015b81811015613c5c5780358352918401918401613c45565b50505080925050509250929050565b6001600160a01b0381168114613c8057600080fd5b50565b8035613c8e81613c6b565b919050565b600082601f830112613ca457600080fd5b613cac613b90565b806040840185811115613cbe57600080fd5b845b81811015613ce1578035613cd381613c6b565b845260209384019301613cc0565b509095945050505050565b60006001600160401b03821115613d0557613d05613b52565b5060051b60200190565b600082601f830112613d2057600080fd5b81356020613d35613d3083613cec565b613bb2565b82815260059290921b84018101918181019086841115613d5457600080fd5b8286015b84811015613d78578035613d6b81613c6b565b8352918301918301613d58565b509695505050505050565b600082601f830112613d9457600080fd5b81356020613da4613d3083613cec565b82815260059290921b84018101918181019086841115613dc357600080fd5b8286015b84811015613d785780358352918301918301613dc7565b600082601f830112613def57600080fd5b613df7613b90565b806040840185811115613e0957600080fd5b845b81811015613ce1578035845260209384019301613e0b565b6000806000806000806101008789031215613e3d57600080fd5b613e478888613c93565b955060408701356001600160401b0380821115613e6357600080fd5b613e6f8a838b01613d0f565b96506060890135915080821115613e8557600080fd5b613e918a838b01613d83565b95506080890135915080821115613ea757600080fd5b50613eb489828a01613d83565b93505060a08701359150613ecb8860c08901613dde565b90509295509295509295565b6001600160a01b03929092168252602082015260400190565b600060208284031215613f0257600080fd5b5035919050565b60008060408385031215613f1c57600080fd5b82359150602083013560048110613f3257600080fd5b809150509250929050565b60006001600160401b03821115613f5657613f56613b52565b50601f01601f191660200190565b600082601f830112613f7557600080fd5b8135613f83613d3082613f3d565b818152846020838601011115613f9857600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114613c8057600080fd5b8035613c8e81613fb5565b6000806000806000806000806000806101808b8d031215613fee57600080fd5b613ff88c8c613c93565b995060408b01356001600160401b038082111561401457600080fd5b6140208e838f01613d0f565b9a5060608d013591508082111561403657600080fd5b6140428e838f01613d83565b995061405060808e01613c83565b985060a08d0135975061406560c08e01613c83565b965060e08d013591508082111561407b57600080fd5b506140888d828e01613f64565b9450506140986101008c01613fc3565b92506101208b013591506140b08c6101408d01613dde565b90509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b60808101818360005b60048110156140ff5781518352602092830192909101906001016140e0565b50505092915050565b60006020828403121561411a57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077f5761077f614121565b600181815b8085111561418557816000190482111561416b5761416b614121565b8085161561417857918102915b93841c939080029061414f565b509250929050565b60008261419c5750600161077f565b816141a95750600061077f565b81600181146141bf57600281146141c9576141e5565b600191505061077f565b60ff8411156141da576141da614121565b50506001821b61077f565b5060208310610133831016604e8410600b8410161715614208575081810a61077f565b614212838361414a565b806000190482111561422657614226614121565b029392505050565b60006126dd838361418d565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561426257600080fd5b81516126dd81613c6b565b60006020828403121561427f57600080fd5b815160ff811681146126dd57600080fd5b60006126dd60ff84168361418d565b6001600160a01b0391909116815260200190565b600081518084526020808501945080840160005b838110156142ec5781516001600160a01b0316875295820195908201906001016142c7565b509495945050505050565b600081518084526020808501945080840160005b838110156142ec5781518752958201959082019060010161430b565b8060005b600781101561212857815184526020938401939091019060010161432b565b60006101c0828a835b600281101561437b5781516001600160a01b0316835260209283019290910190600101614353565b5050508060408401526143908184018a6142b3565b905082810360608401526143a481896142f7565b905082810360808401526143b881886142f7565b905082810360a08401526143cc81876142f7565b905082810360c08401526143e081866142f7565b9150506143f060e0830184614327565b98975050505050505050565b60008060006060848603121561441157600080fd5b8351925060208401519150604084015190509250925092565b6000825161443c818460208701613aef565b9190910192915050565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b60006020828403121561448c57600080fd5b81516126dd81613fb5565b808202811582820484141761077f5761077f614121565b634e487b7160e01b600052601260045260246000fd5b6000826144d3576144d36144ae565b500490565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561451557600080fd5b505080516020909101519092909150565b8082018082111561077f5761077f614121565b808201828112600083128015821682158216171561455957614559614121565b505092915050565b818103600083128015838313168383128216171561458157614581614121565b5092915050565b600082614597576145976144ae565b600160ff1b8214600019841416156145b1576145b1614121565b500590565b600082601f8301126145c757600080fd5b81516145d5613d3082613f3d565b8181528460208386010111156145ea57600080fd5b61391b826020830160208701613aef565b600080604080848603121561460f57600080fd5b83516001600160401b038082111561462657600080fd5b818601915086601f83011261463a57600080fd5b8151602061464a613d3083613cec565b82815260079290921b8401810191818101908a84111561466957600080fd5b948201945b838610156146e3576080868c0312156146875760008081fd5b61468f613b68565b865161469a81613c6b565b8152868401516146a981613c6b565b81850152868801516146ba81613c6b565b818901526060878101516146cd81613c6b565b908201528252608095909501949082019061466e565b918901519197509094505050808311156146fc57600080fd5b505061470a858286016145b6565b9150509250929050565b6000806000806080858703121561472a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6060808252845182820181905260009190608090818501906020808a01865b838110156147b157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614769565b50508601979097526040909401949094525090949350505050565b600060018060a01b03808916835260c060208401526147ee60c0840189613b13565b9681166040840152949094166060820152608081019290925260a090910152509291505056fe5042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a2646970667358221220c8a99e8b5addb5b446bc3b4ddddfcec75611a6c57eb3f5a39866806e9265f0cd64736f6c63430008110033", + "numDeployments": 16, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fuseStatus\",\"type\":\"uint256\"}],\"name\":\"FuseStatusChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[4]\",\"name\":\"newFuseThresholds\",\"type\":\"uint256[4]\"}],\"name\":\"NewFuseThresholds\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountToSwap\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountIn\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"expectedAmountOut\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetIn\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetOut\",\"type\":\"address\"}],\"name\":\"SwapByAgg\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ENTRY_TO_POOL_IS_ALLOWED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_LOWER_LIMIT_OFF\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_LOWER_LIMIT_ON\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_UPPER_LIMIT_OFF\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FUSE_IDX_UPPER_LIMIT_ON\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GAP_AMOUNT_TO_SWAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_POOL\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_TOKEN_A\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_ADDR_DEFAULT_STATE_TOKEN_B\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_FUSE_STATUS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_2\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_3\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_RESERVED_4\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_0\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_2\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_THRESHOLD_3\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_LOWER_TICK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_TICK_SPACING\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"IDX_TICK_DEFAULT_STATE_UPPER_TICK\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_ASSET\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_REBALANCE_TICK_RANGE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCORRECT_TICK_RANGE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNKNOWN_SWAP_ROUTER\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"poolPriceDecimals\",\"type\":\"uint256\"}],\"name\":\"getPoolPriceAdjustment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"adjustment\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"The library contains quoteWithdrawStep/withdrawStep-related logic\",\"kind\":\"dev\",\"methods\":{\"quoteWithdrawStep(address[2],address[],uint256[],uint256[],uint256,uint256[2])\":{\"params\":{\"amountsFromPool\":\"Amounts of {tokens} that will be received from the pool before calling withdraw\",\"converterLiquidator_\":\"[TetuConverter, TetuLiquidator]\",\"entryDataValues\":\"[propNotUnderlying18, entryDataParam] propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18]. The leftovers should be swapped to get following result proportions of the assets: not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18 Value type(uint).max means that the proportions should be read from the pool. entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\",\"liquidationThresholds\":\"Liquidation thresholds for the {tokens}\",\"tokens\":\"Tokens used by depositor (length == 2: underlying and not-underlying)\"},\"returns\":{\"amountToSwap\":\"Amount that will be swapped on the next swap. 0 - no swap This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\",\"tokenToSwap\":\"Address of the token that will be swapped on the next swap. 0 - no swap\"}},\"withdrawStep(address[2],address[],uint256[],address,uint256,address,bytes,bool,uint256,uint256[2])\":{\"params\":{\"aggregator_\":\"Aggregator that should be used for the next swap. 0 - no swap\",\"amountToSwap_\":\"Amount that will be swapped on the next swap. 0 - no swap\",\"converterLiquidator_\":\"[TetuConverter, TetuLiquidator]\",\"entryDataValues\":\"[propNotUnderlying18, entryDataParam] propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18]. The leftovers should be swapped to get following result proportions of the assets: not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18 entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\",\"liquidationThresholds\":\"Liquidation thresholds for the {tokens}\",\"planKind\":\"One of IterationPlanLib.PLAN_XXX\",\"swapData_\":\"Swap data to be passed to the aggregator on the next swap. Swap data contains swap-route, amount and all other required info for the swap. Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\",\"tokenToSwap_\":\"Address of the token that will be swapped on the next swap. 0 - no swap\",\"tokens\":\"Tokens used by depositor (length == 2: underlying and not-underlying)\",\"useLiquidator_\":\"Use liquidator instead of aggregator. Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}. Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}. It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false - the liquidator will be used in same way as aggregator in this case.\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to the required proportions\"}}},\"stateVariables\":{\"OPENOCEAN\":{\"details\":\"See https://docs.openocean.finance/dev/contracts-of-chains\"},\"OPENOCEAN_ZKEVM\":{\"details\":\"See https://docs.openocean.finance/dev/contracts-of-chains\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"ENTRY_TO_POOL_IS_ALLOWED()\":{\"notice\":\"Enter to the pool at the end of withdrawByAggStep\"},\"ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED()\":{\"notice\":\"Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\"},\"FUSE_IDX_LOWER_LIMIT_ON()\":{\"notice\":\"Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF] If the price falls below LOWER_LIMIT_ON the fuse is turned ON When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF Example: [0.9, 0.92, 1.08, 1.1] Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF. Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\"},\"GAP_AMOUNT_TO_SWAP()\":{\"notice\":\"A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\"},\"quoteWithdrawStep(address[2],address[],uint256[],uint256[],uint256,uint256[2])\":{\"notice\":\"Get info for the swap that will be made on the next call of {withdrawStep}\"},\"withdrawStep(address[2],address[],uint256[],address,uint256,address,bytes,bool,uint256,uint256[2])\":{\"notice\":\"Make withdraw step with 0 or 1 swap only. The step can make one of the following actions: 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\"}},\"notice\":\"Library for the UniV3-like strategies with two tokens in the pool\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyLib.sol\":\"PairBasedStrategyLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x61486c61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106102475760003560e01c8063767e17e811610145578063c143e087116100c2578063d7a1d53511610086578063d7a1d535146102e8578063e0c24b3a1461042e578063e642319514610436578063ec88f9ff146102a2578063f7ebc365146102a257600080fd5b8063c143e08714610313578063c63891c7146102a2578063c8ce726c146102e0578063cdb549351461041e578063d3a9335c1461042657600080fd5b8063a200f62b11610109578063a200f62b146102e0578063a7231ef6146103da578063aea02d91146103e2578063c00d3e0b146102e8578063c06ab65f146103ea57600080fd5b8063767e17e8146102e0578063831fd9ea146103135780638f875cc814610313578063927154f0146103a75780639c2d8d63146102e857600080fd5b806337d11dc1116101d357806360339c591161019757806360339c59146102e8578063603938b814610313578063673d63db1461031b5780636bffb346146103575780637545be261461037757600080fd5b806337d11dc1146102e857806343fc304a146102f057806346326a29146102f8578063556ce728146103005780635be05524146102e057600080fd5b8063137c52b21161021a578063137c52b2146102a25780631429888b146102aa57806314ad109e146102b2578063217052d1146102a257806335f33bc2146102e057600080fd5b8063058ba3db1461024c5780630593c4c91461026a5780631033193e1461028c5780631200fb3c146102a2575b600080fd5b61025461043e565b6040516102619190613b3f565b60405180910390f35b81801561027657600080fd5b5061028a610285366004613be2565b61045a565b005b610294600981565b604051908152602001610261565b610294600181565b610294600781565b8180156102be57600080fd5b506102d26102cd366004613e23565b6105f6565b604051610261929190613ed7565b610294600281565b610294600081565b610294600c81565b610294600a81565b61029461030e366004613ef0565b610758565b610294600381565b6102546040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525081565b81801561036357600080fd5b5061028a610372366004613f09565b610785565b81801561038357600080fd5b50610397610392366004613fce565b6107e9565b6040519015158152602001610261565b610254604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b81525081565b610294600b81565b610294600581565b61025460405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525081565b610294606481565b610294600481565b610294600681565b610294600881565b6040518060600160405280602281526020016148156022913981565b805115801561046b57506020810151155b8061047b57506020810151815111155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906104ce5760405162461bcd60e51b81526004016104c59190613b3f565b60405180910390fd5b5060408101511580156104e357506060810151155b806104f657506060810151604082015110155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906105405760405162461bcd60e51b81526004016104c59190613b3f565b508051158015906105545750604081015115155b156105ab5780516040808301518151808301909252601382527254532d333020696e76616c69642076616c756560681b60208301529091106105a95760405162461bcd60e51b81526004016104c59190613b3f565b505b6105ba60018301826004613a9c565b507fef6880b7ef7308e1a0fdc54890042b9fc1d2355795cd67a12c76d38438e643b5816040516105ea91906140d7565b60405180910390a15050565b600080808061061661060e8b835b60200201516109b6565b8a6002610a7b565b9150915060006040518061016001604052808c60006002811061063b5761063b6140c1565b60200201516001600160a01b031681526020018c600160028110610661576106616140c1565b60200201516001600160a01b031681526020018b81526020018a8152602001848152602001838152602001898152602001888152602001600019886000600281106106ae576106ae6140c1565b6020020151146106bf578751610721565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107219190614108565b8152875160001914602082015260400187600160200201519052905061074681610c69565b94509450505050965096945050505050565b60006012821061076957600161077f565b610774826012614137565b61077f90600a61422e565b92915050565b81548190839060ff191660018360038111156107a3576107a361423a565b02179055507f5a7ee3c5ef7f4e3625ee638c3a95481dc4cbfaceda022d1e8fba8ed7fa2208e18160038111156107db576107db61423a565b6040519081526020016105ea565b600080806108026107fa8e83610604565b8d6002610a7b565b9150915060006040518061016001604052808f600060028110610827576108276140c1565b60200201516001600160a01b031681526020018f60016002811061084d5761084d6140c1565b60200201516001600160a01b031681526020018e81526020018d815260200184815260200183815260200160026001600160401b0381111561089157610891613b52565b6040519080825280602002602001820160405280156108ba578160200160208202803683370190505b508152602081018890528651604090910190600019146108db57865161093d565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093d9190614108565b815286516000191460208201526040018660016020020151815250905060006040518060a0016040528089151581526020018d6001600160a01b031681526020018b6001600160a01b031681526020018c81526020018a81525090506109a38282610ddc565b9f9e505050505050505050505050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1a9190614250565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a57573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614250565b606080826001600160401b03811115610a9657610a96613b52565b604051908082528060200260200182016040528015610abf578160200160208202803683370190505b509150826001600160401b03811115610ada57610ada613b52565b604051908082528060200260200182016040528015610b03578160200160208202803683370190505b50905060005b83811015610c6057848181518110610b2357610b236140c1565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c919061426d565b610b9790600a614290565b828281518110610ba957610ba96140c1565b602002602001018181525050856001600160a01b031663b3596f07868381518110610bd657610bd66140c1565b60200260200101516040518263ffffffff1660e01b8152600401610bfa919061429f565b602060405180830381865afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3b9190614108565b838281518110610c4d57610c4d6140c1565b6020908102919091010152600101610b09565b50935093915050565b6000806000730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528087600001516001600160a01b03166001600160a01b0316815260200187602001516001600160a01b03166001600160a01b03168152508660400151876060015188608001518960a001518a60c001516040518060e001604052808d6101200151610cfe576000610d01565b60015b60ff1681526020018d60e0015181526020018d61010001518152602001600019815260200160008152602001600181526020018d61014001518152506040518863ffffffff1660e01b8152600401610d5f979695949392919061434a565b606060405180830381865af4158015610d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da091906143fc565b50925090508015610dd6576040840151610dbb600183614137565b81518110610dcb57610dcb6140c1565b602002602001015192505b50915091565b600080600080730118015B5D5F7f104292DB79Ae47AA0e962A09be632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b0316815250886040015189606001518a608001518b60a001518c60c001516040518060e001604052808f6101200151610e72576000610e75565b60015b60ff1681526020018f60e0015181526020018f61010001518152602001600019815260200160008152602001600181526020018f61014001518152506040518863ffffffff1660e01b8152600401610ed3979695949392919061434a565b606060405180830381865af4158015610ef0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1491906143fc565b9250925092506000604051806080016040528060028960e001511480610f3c575060e0890151155b15151515815260200160018960e001511480610f5a575060e0890151155b1515815260e0890180516001908114602084015290511460409091015290508315801590610f86575080515b15610fc557610fbd8787610f9b600188614137565b6000610fa860018a614137565b14610fb4576000610fb7565b60015b8761124f565b610100890152505b8115801590610fd5575060208101515b156110e357865160408801516110df91906000610ff3600187614137565b14610fff576000611002565b60015b81518110611012576110126140c1565b6020026020010151896040015160018661102c9190614137565b8151811061103c5761103c6140c1565b60200260200101518a604001516001876110569190614137565b81518110611066576110666140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611099919061429f565b602060405180830381865afa1580156110b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110da9190614108565b6118af565b5050505b8315611244576040810151156111fd576111038787610f9b600188614137565b610100890152506060810151801561111a57508115155b156111f8576000806111518982611132600188614137565b1461113e576000611141565b60015b61114c600188614137565b611a73565b9150915080156111925761118d8961116a600187614137565b6000611177600189614137565b14611183576000611186565b60015b6001612008565b6111f5565b60608901516111a2600186614137565b815181106111b2576111b26140c1565b60200260200101518211156111f5576111f58960006111d2600188614137565b146111de5760006111e1565b60015b6111ec600188614137565b8560001961212e565b50505b611244565b8115801561120d57508661012001515b801561121d575061010087015115155b80156112365750866101000151670de0b6b3a764000014155b156112445761124487612408565b501595945050505050565b600080856000015161126357856060015192505b855160009061127657866040015161127c565b87602001515b905087604001518681518110611294576112946140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112c7919061429f565b602060405180830381865afa1580156112e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113089190614108565b8411156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906113595760405162461bcd60e51b81526004016104c59190613b3f565b5087604001518681518110611370576113706140c1565b60200260200101516001600160a01b031687602001516001600160a01b0316146040518060400160405280601181526020017054532d323520737761702062792061676760781b815250906113d85760405162461bcd60e51b81526004016104c59190613b3f565b50876060015186815181106113ef576113ef6140c1565b60200260200101518411156118275761142688604001518781518110611417576114176140c1565b602002602001015185836125eb565b600061144e89604001518781518110611441576114416140c1565b602002602001015161265c565b8851909150156114de576114668589606001516126cc565b94506114d68960000151838b604001518a81518110611487576114876140c1565b60200260200101518c604001518a815181106114a5576114a56140c1565b60200260200101518961012c8f606001518e815181106114c7576114c76140c1565b602002602001015160016126e4565b509350611591565b88602001516001600160a01b0316826001600160a01b03161461150457611504826127ef565b600080836001600160a01b03168a60800151604051611523919061442a565b6000604051808303816000865af19150503d8060008114611560576040519150601f19603f3d011682016040523d82523d6000602084013e611565565b606091505b509150915081819061158a5760405162461bcd60e51b81526004016104c59190613b3f565b5086955050505b88600001516001600160a01b031663291f89c48a6040015189815181106115ba576115ba6140c1565b6020026020010151878c604001518a815181106115d9576115d96140c1565b6020026020010151856115fb8f604001518d81518110611441576114416140c1565b6116059190614137565b61012c6040518663ffffffff1660e01b8152600401611628959493929190614446565b602060405180830381865afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611669919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906116b25760405162461bcd60e51b81526004016104c59190613b3f565b507f650da787b25801954b4e03c78b9c6b07fddcbda246347411c49d282c7225f592886060015186836116f48d604001518b81518110611441576114416140c1565b6116fe9190614137565b8c60a001518b81518110611714576117146140c1565b60200260200101518d608001518b81518110611732576117326140c1565b60200260200101518e60a001518c81518110611750576117506140c1565b60200260200101518f608001518e8151811061176e5761176e6140c1565b60200260200101518c6117819190614497565b61178b9190614497565b61179591906144c4565b61179f91906144c4565b868e604001518d815181106117b6576117b66140c1565b60200260200101518f604001518d815181106117d4576117d46140c1565b602090810291909101810151604080519889529188019690965286019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e00160405180910390a1505b8288610120015161183d5788610100015161189f565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190614108565b92509250505b9550959350505050565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118e1919061429f565b602060405180830381865afa1580156118fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119229190614108565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b815260040161195994939291906144d8565b60408051808303816000875af1158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190614502565b5090506119b68187106119ae57816119b0565b865b836126cc565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3c9190614502565b909650905080861115611a5657611a538187614137565b95505b611a638a8a8a87876128ac565b9550505050509450945094915050565b600080611aaf6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8560a001518581518110611ac557611ac56140c1565b602002602001015186608001518681518110611ae357611ae36140c1565b602002602001015187604001518781518110611b0157611b016140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611b34919061429f565b602060405180830381865afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190614108565b611b7f9190614497565b611b8991906144c4565b604082015260a0860151805185908110611ba557611ba56140c1565b602002602001015186608001518581518110611bc357611bc36140c1565b602002602001015187604001518681518110611be157611be16140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611c14919061429f565b602060405180830381865afa158015611c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c559190614108565b611c5f9190614497565b611c6991906144c4565b60608201528415611c7f57856101000151611c97565b610100860151611c9790670de0b6b3a7640000614137565b81528415611cbc57610100860151611cb790670de0b6b3a7640000614137565b611cc3565b8561010001515b602082015260a0860151805186908110611cdf57611cdf6140c1565b602002602001015186608001518581518110611cfd57611cfd6140c1565b60200260200101518760a001518681518110611d1b57611d1b6140c1565b602002602001015188608001518881518110611d3957611d396140c1565b6020026020010151611d4b9190614497565b611d5d90670de0b6b3a7640000614497565b611d6791906144c4565b611d7191906144c4565b81608001818152505060008087600001516001600160a01b031663e4c2be70308a604001518a81518110611da757611da76140c1565b60200260200101518b604001518a81518110611dc557611dc56140c1565b602002602001015160016040518563ffffffff1660e01b8152600401611dee94939291906144d8565b6040805180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614502565b9150915081600003611f0e5760208301518351600091611e4d91614526565b845160608601516040870151611e639190614526565b611e6d9190614497565b611e7791906144c4565b9050836040015181118015611f0657508860a001518881518110611e9d57611e9d6140c1565b602002602001015189608001518981518110611ebb57611ebb6140c1565b60200260200101518a606001518a81518110611ed957611ed96140c1565b6020026020010151611eeb9190614497565b611ef591906144c4565b6040850151611f049083614137565b115b945050611faa565b8260000151670de0b6b3a7640000838386608001518760200151611f329190614497565b611f3c9190614497565b611f4691906144c4565b611f5091906144c4565b611f5a9190614539565b83604001518460200151611f6e9190614497565b60608501518551611f7f9190614497565b611f899190614561565b611f939190614588565b60a0840181905260001215611faa578260a0015194505b87608001518681518110611fc057611fc06140c1565b60200260200101518860a001518781518110611fde57611fde6140c1565b602002602001015186611ff19190614497565b611ffb91906144c4565b9450505050935093915050565b61212884848487604001518781518110612024576120246140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612057919061429f565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614108565b886040015187815181106120ae576120ae6140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120e1919061429f565b602060405180830381865afa1580156120fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121229190614108565b86612a95565b50505050565b600085604001518481518110612146576121466140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612179919061429f565b602060405180830381865afa158015612196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ba9190614108565b90506122068660000151876040015187815181106121da576121da6140c1565b6020026020010151886040015187815181106121f8576121f86140c1565b6020026020010151866118af565b505050600086604001518581518110612221576122216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612254919061429f565b602060405180830381865afa158015612271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122959190614108565b905060008183116122a75760006122b1565b6122b18284614137565b905084811080156122e95750876060015186815181106122d3576122d36140c1565b602002602001015181866122e79190614137565b115b156123fe57600088600001516001600160a01b031663e4c2be70308b604001518b8151811061231a5761231a6140c1565b60200260200101518c604001518b81518110612338576123386140c1565b602002602001015160016040518563ffffffff1660e01b815260040161236194939291906144d8565b6040805180830381865afa15801561237d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a19190614502565b509050886060015187815181106123ba576123ba6140c1565b6020026020010151811180156123cf57508481105b156123ef576123ea8989896123e4868b614137565b8561212e565b6123fc565b6123fc89888a6000612008565b505b5050505050505050565b60008160400151600081518110612421576124216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612454919061429f565b602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614108565b9050600082604001516001815181106124b0576124b06140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016124e3919061429f565b602060405180830381865afa158015612500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125249190614108565b905060008061254785608001518660a00151868689610100015160006001612db8565b915091508184111561259a57846060015160008151811061256a5761256a6140c1565b6020026020010151828561257e9190614137565b111561259557612595856000600187876001612a95565b6125e4565b808311156125e45784606001516000815181106125b9576125b96140c1565b602002602001015181846125cd9190614137565b11156125e4576125e4856001600086886001612a95565b5050505050565b60405163095ea7b360e01b81526001600160a01b0384169063095ea7b3906126199084908690600401613ed7565b6020604051808303816000875af1158015612638573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061447a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061268b90309060040161429f565b602060405180830381865afa1580156126a8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614108565b60008183106126db57816126dd565b825b9392505050565b6000808386116126f9575060009050806127e2565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa15801561274b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261277391908101906145fb565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506127ca5760405162461bcd60e51b81526004016104c59190613b3f565b50866127dc8c838d8d8d8d8d8c612f47565b92509250505b9850989650505050505050565b6001600160a01b038116731111111254eeb25477b68fb85ed929f73a960582148061283657506001600160a01b038116736352a56caadc4f1e25cd6c75970fa768a3304e64145b8061285d57506001600160a01b038116736dd434082eab5cd134b33719ec1ff05fe985b97b145b604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b815250906128a85760405162461bcd60e51b81526004016104c59190613b3f565b5050565b600080606484106118a5576128cb6001600160a01b0386168886613225565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561292c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129509190614714565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906129e590309060040161429f565b602060405180830381865afa158015612a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a269190614108565b9050808511612a36576000612a40565b612a408186614137565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b60208201529093508215612a885760405162461bcd60e51b81526004016104c59190613b3f565b5050509550959350505050565b8015612bac57600086600001516001600160a01b031663e4c2be703089604001518881518110612ac757612ac76140c1565b60200260200101518a604001518a81518110612ae557612ae56140c1565b602002602001015160006040518563ffffffff1660e01b8152600401612b0e94939291906144d8565b6040805180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614502565b509050606481106040518060400160405280601a81526020017f54532d3239206f70706f7369746520646562742065786973747300000000000081525090612ba95760405162461bcd60e51b81526004016104c59190613b3f565b50505b600060405180610160016040528060405180604001604052808a600001516001600160a01b031681526020018a602001516001600160a01b0316815250815260200188604001518881518110612c0457612c046140c1565b60200260200101516001600160a01b0316815260200188604001518781518110612c3057612c306140c1565b60200260200101516001600160a01b0316815260200160008814612c5957886101000151612c71565b610100890151612c7190670de0b6b3a7640000614137565b81526020018715612c9957610100890151612c9490670de0b6b3a7640000614137565b612ca0565b8861010001515b81526020018860a001518781518110612cbb57612cbb6140c1565b602002602001015189608001518981518110612cd957612cd96140c1565b60200260200101518a60a001518a81518110612cf757612cf76140c1565b60200260200101518b608001518a81518110612d1557612d156140c1565b6020026020010151670de0b6b3a7640000612d309190614497565b612d3a9190614497565b612d4491906144c4565b612d4e91906144c4565b815260200188606001518881518110612d6957612d696140c1565b6020026020010151815260200160008152602001600081526020018781526020018681525090506123fc8160405180604001604052808a6080015181526020018a60a001518152508686613280565b6000806000888581518110612dcf57612dcf6140c1565b60200260200101518a8681518110612de957612de96140c1565b602002602001015189612dfc9190614497565b612e0691906144c4565b90506000898581518110612e1c57612e1c6140c1565b60200260200101518b8681518110612e3657612e366140c1565b602002602001015189612e499190614497565b612e5391906144c4565b90508615612e8857670de0b6b3a764000087612e6f8385614526565b612e799190614497565b612e8391906144c4565b612e8b565b60005b92508a8681518110612e9f57612e9f6140c1565b60200260200101518a8781518110612eb957612eb96140c1565b6020026020010151848385612ece9190614526565b612ed89190614137565b612ee29190614497565b612eec91906144c4565b93508a8581518110612f0057612f006140c1565b60200260200101518a8681518110612f1a57612f1a6140c1565b602002602001015184612f2d9190614497565b612f3791906144c4565b9250505097509795505050505050565b6000612f548685896133ed565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612f8390309060040161429f565b602060405180830381865afa158015612fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc49190614108565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890612ff7908c908990899060040161474a565b600060405180830381600087803b15801561301157600080fd5b505af1158015613025573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a082319061305890309060040161429f565b602060405180830381865afa158015613075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130999190614108565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906130eb5760405162461bcd60e51b81526004016104c59190613b3f565b506130f68282614137565b925083806131745750604051630a47e27160e21b81526001600160a01b038c169063291f89c490613133908b908a908c9089908c90600401614446565b602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613174919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906131bd5760405162461bcd60e51b81526004016104c59190613b3f565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b61327b8363a9059cbb60e01b8484604051602401613244929190613ed7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613498565b505050565b6000808560e00151600014806132995750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906132e35760405162461bcd60e51b81526004016104c59190613b3f565b506101008601511561335e57856101000151831061331f576133168685886101000151866133119190614137565b61356a565b915091506133e4565b600061333d878787878b61010001516133389190614137565b613703565b5090506133548761334e8388614137565b8661356a565b92509250506133e4565b60e0860151156133d9578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906133be5760405162461bcd60e51b81526004016104c59190613b3f565b50613316868760e00151866133d39190614137565b8561356a565b61331686858561356a565b94509492505050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561343c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134609190614108565b101561327b5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390612619908490600160ff1b90600401613ed7565b60006134ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661390c9092919063ffffffff16565b80519091501561327b578080602001905181019061350b919061447a565b61327b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104c5565b60608381015160808086015160408051600160208201528082019490945283850191909152805180840390940184529101905260009081908190841561363a57670de0b6b3a7640000876080015188606001518960a00151886135cd9190614497565b6135d79190614497565b6135e191906144c4565b6135eb91906144c4565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b815250906136385760405162461bcd60e51b81526004016104c59190613b3f565b505b60208701516136559061364d8489614137565b8951516133ed565b732af59Be93d77B391Fea20322407fE46907Bf9D0E63ca27d10d886000015160000151838a602001518b60400151878c61368f9190614137565b8d60c001516040518763ffffffff1660e01b81526004016136b5969594939291906147cc565b6040805180830381865af41580156136d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f59190614502565b935093505050935093915050565b6000806000856020015187610140015181518110613723576137236140c1565b6020026020010151866000015188610120015181518110613746576137466140c1565b6020026020010151876020015189610120015181518110613769576137696140c1565b602002602001015188600001518a61014001518151811061378c5761378c6140c1565b60200260200101518761379f9190614497565b6137a99190614497565b6137b391906144c4565b6137bd91906144c4565b9050620186a06137cf61012c82614526565b6137d99083614497565b6137e391906144c4565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906138365760405162461bcd60e51b81526004016104c59190613b3f565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e4820152732af59Be93d77B391Fea20322407fE46907Bf9D0E90637de8f56990610104016040805180830381865af41580156138da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fe9190614502565b909890975095505050505050565b606061391b8484600085613923565b949350505050565b6060824710156139845760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104c5565b600080866001600160a01b031685876040516139a0919061442a565b60006040518083038185875af1925050503d80600081146139dd576040519150601f19603f3d011682016040523d82523d6000602084013e6139e2565b606091505b50915091506139f3878383876139fe565b979650505050505050565b60608315613a6d578251600003613a66576001600160a01b0385163b613a665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104c5565b508161391b565b61391b8383815115613a825781518083602001fd5b8060405162461bcd60e51b81526004016104c59190613b3f565b8260048101928215613aca579160200282015b82811115613aca578251825591602001919060010190613aaf565b50613ad6929150613ada565b5090565b5b80821115613ad65760008155600101613adb565b60005b83811015613b0a578181015183820152602001613af2565b50506000910152565b60008151808452613b2b816020860160208601613aef565b601f01601f19169290920160200192915050565b6020815260006126dd6020830184613b13565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613b8a57613b8a613b52565b60405290565b604080519081016001600160401b0381118282101715613b8a57613b8a613b52565b604051601f8201601f191681016001600160401b0381118282101715613bda57613bda613b52565b604052919050565b60008060a08385031215613bf557600080fd5b82359150602084603f850112613c0a57600080fd5b604051608081018181106001600160401b0382111715613c2c57613c2c613b52565b6040528060a0860187811115613c4157600080fd5b8387015b81811015613c5c5780358352918401918401613c45565b50505080925050509250929050565b6001600160a01b0381168114613c8057600080fd5b50565b8035613c8e81613c6b565b919050565b600082601f830112613ca457600080fd5b613cac613b90565b806040840185811115613cbe57600080fd5b845b81811015613ce1578035613cd381613c6b565b845260209384019301613cc0565b509095945050505050565b60006001600160401b03821115613d0557613d05613b52565b5060051b60200190565b600082601f830112613d2057600080fd5b81356020613d35613d3083613cec565b613bb2565b82815260059290921b84018101918181019086841115613d5457600080fd5b8286015b84811015613d78578035613d6b81613c6b565b8352918301918301613d58565b509695505050505050565b600082601f830112613d9457600080fd5b81356020613da4613d3083613cec565b82815260059290921b84018101918181019086841115613dc357600080fd5b8286015b84811015613d785780358352918301918301613dc7565b600082601f830112613def57600080fd5b613df7613b90565b806040840185811115613e0957600080fd5b845b81811015613ce1578035845260209384019301613e0b565b6000806000806000806101008789031215613e3d57600080fd5b613e478888613c93565b955060408701356001600160401b0380821115613e6357600080fd5b613e6f8a838b01613d0f565b96506060890135915080821115613e8557600080fd5b613e918a838b01613d83565b95506080890135915080821115613ea757600080fd5b50613eb489828a01613d83565b93505060a08701359150613ecb8860c08901613dde565b90509295509295509295565b6001600160a01b03929092168252602082015260400190565b600060208284031215613f0257600080fd5b5035919050565b60008060408385031215613f1c57600080fd5b82359150602083013560048110613f3257600080fd5b809150509250929050565b60006001600160401b03821115613f5657613f56613b52565b50601f01601f191660200190565b600082601f830112613f7557600080fd5b8135613f83613d3082613f3d565b818152846020838601011115613f9857600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114613c8057600080fd5b8035613c8e81613fb5565b6000806000806000806000806000806101808b8d031215613fee57600080fd5b613ff88c8c613c93565b995060408b01356001600160401b038082111561401457600080fd5b6140208e838f01613d0f565b9a5060608d013591508082111561403657600080fd5b6140428e838f01613d83565b995061405060808e01613c83565b985060a08d0135975061406560c08e01613c83565b965060e08d013591508082111561407b57600080fd5b506140888d828e01613f64565b9450506140986101008c01613fc3565b92506101208b013591506140b08c6101408d01613dde565b90509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b60808101818360005b60048110156140ff5781518352602092830192909101906001016140e0565b50505092915050565b60006020828403121561411a57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077f5761077f614121565b600181815b8085111561418557816000190482111561416b5761416b614121565b8085161561417857918102915b93841c939080029061414f565b509250929050565b60008261419c5750600161077f565b816141a95750600061077f565b81600181146141bf57600281146141c9576141e5565b600191505061077f565b60ff8411156141da576141da614121565b50506001821b61077f565b5060208310610133831016604e8410600b8410161715614208575081810a61077f565b614212838361414a565b806000190482111561422657614226614121565b029392505050565b60006126dd838361418d565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561426257600080fd5b81516126dd81613c6b565b60006020828403121561427f57600080fd5b815160ff811681146126dd57600080fd5b60006126dd60ff84168361418d565b6001600160a01b0391909116815260200190565b600081518084526020808501945080840160005b838110156142ec5781516001600160a01b0316875295820195908201906001016142c7565b509495945050505050565b600081518084526020808501945080840160005b838110156142ec5781518752958201959082019060010161430b565b8060005b600781101561212857815184526020938401939091019060010161432b565b60006101c0828a835b600281101561437b5781516001600160a01b0316835260209283019290910190600101614353565b5050508060408401526143908184018a6142b3565b905082810360608401526143a481896142f7565b905082810360808401526143b881886142f7565b905082810360a08401526143cc81876142f7565b905082810360c08401526143e081866142f7565b9150506143f060e0830184614327565b98975050505050505050565b60008060006060848603121561441157600080fd5b8351925060208401519150604084015190509250925092565b6000825161443c818460208701613aef565b9190910192915050565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b60006020828403121561448c57600080fd5b81516126dd81613fb5565b808202811582820484141761077f5761077f614121565b634e487b7160e01b600052601260045260246000fd5b6000826144d3576144d36144ae565b500490565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561451557600080fd5b505080516020909101519092909150565b8082018082111561077f5761077f614121565b808201828112600083128015821682158216171561455957614559614121565b505092915050565b818103600083128015838313168383128216171561458157614581614121565b5092915050565b600082614597576145976144ae565b600160ff1b8214600019841416156145b1576145b1614121565b500590565b600082601f8301126145c757600080fd5b81516145d5613d3082613f3d565b8181528460208386010111156145ea57600080fd5b61391b826020830160208701613aef565b600080604080848603121561460f57600080fd5b83516001600160401b038082111561462657600080fd5b818601915086601f83011261463a57600080fd5b8151602061464a613d3083613cec565b82815260079290921b8401810191818101908a84111561466957600080fd5b948201945b838610156146e3576080868c0312156146875760008081fd5b61468f613b68565b865161469a81613c6b565b8152868401516146a981613c6b565b81850152868801516146ba81613c6b565b818901526060878101516146cd81613c6b565b908201528252608095909501949082019061466e565b918901519197509094505050808311156146fc57600080fd5b505061470a858286016145b6565b9150509250929050565b6000806000806080858703121561472a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6060808252845182820181905260009190608090818501906020808a01865b838110156147b157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614769565b50508601979097526040909401949094525090949350505050565b600060018060a01b03808916835260c060208401526147ee60c0840189613b13565b9681166040840152949094166060820152608081019290925260a090910152509291505056fe5042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a26469706673582212207f7752bf16958260345ca337e20a634d0ac44946dd9dffcf9ee3083394e513cf64736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106102475760003560e01c8063767e17e811610145578063c143e087116100c2578063d7a1d53511610086578063d7a1d535146102e8578063e0c24b3a1461042e578063e642319514610436578063ec88f9ff146102a2578063f7ebc365146102a257600080fd5b8063c143e08714610313578063c63891c7146102a2578063c8ce726c146102e0578063cdb549351461041e578063d3a9335c1461042657600080fd5b8063a200f62b11610109578063a200f62b146102e0578063a7231ef6146103da578063aea02d91146103e2578063c00d3e0b146102e8578063c06ab65f146103ea57600080fd5b8063767e17e8146102e0578063831fd9ea146103135780638f875cc814610313578063927154f0146103a75780639c2d8d63146102e857600080fd5b806337d11dc1116101d357806360339c591161019757806360339c59146102e8578063603938b814610313578063673d63db1461031b5780636bffb346146103575780637545be261461037757600080fd5b806337d11dc1146102e857806343fc304a146102f057806346326a29146102f8578063556ce728146103005780635be05524146102e057600080fd5b8063137c52b21161021a578063137c52b2146102a25780631429888b146102aa57806314ad109e146102b2578063217052d1146102a257806335f33bc2146102e057600080fd5b8063058ba3db1461024c5780630593c4c91461026a5780631033193e1461028c5780631200fb3c146102a2575b600080fd5b61025461043e565b6040516102619190613b3f565b60405180910390f35b81801561027657600080fd5b5061028a610285366004613be2565b61045a565b005b610294600981565b604051908152602001610261565b610294600181565b610294600781565b8180156102be57600080fd5b506102d26102cd366004613e23565b6105f6565b604051610261929190613ed7565b610294600281565b610294600081565b610294600c81565b610294600a81565b61029461030e366004613ef0565b610758565b610294600381565b6102546040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525081565b81801561036357600080fd5b5061028a610372366004613f09565b610785565b81801561038357600080fd5b50610397610392366004613fce565b6107e9565b6040519015158152602001610261565b610254604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b81525081565b610294600b81565b610294600581565b61025460405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525081565b610294606481565b610294600481565b610294600681565b610294600881565b6040518060600160405280602281526020016148156022913981565b805115801561046b57506020810151155b8061047b57506020810151815111155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906104ce5760405162461bcd60e51b81526004016104c59190613b3f565b60405180910390fd5b5060408101511580156104e357506060810151155b806104f657506060810151604082015110155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906105405760405162461bcd60e51b81526004016104c59190613b3f565b508051158015906105545750604081015115155b156105ab5780516040808301518151808301909252601382527254532d333020696e76616c69642076616c756560681b60208301529091106105a95760405162461bcd60e51b81526004016104c59190613b3f565b505b6105ba60018301826004613a9c565b507fef6880b7ef7308e1a0fdc54890042b9fc1d2355795cd67a12c76d38438e643b5816040516105ea91906140d7565b60405180910390a15050565b600080808061061661060e8b835b60200201516109b6565b8a6002610a7b565b9150915060006040518061016001604052808c60006002811061063b5761063b6140c1565b60200201516001600160a01b031681526020018c600160028110610661576106616140c1565b60200201516001600160a01b031681526020018b81526020018a8152602001848152602001838152602001898152602001888152602001600019886000600281106106ae576106ae6140c1565b6020020151146106bf578751610721565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107219190614108565b8152875160001914602082015260400187600160200201519052905061074681610c69565b94509450505050965096945050505050565b60006012821061076957600161077f565b610774826012614137565b61077f90600a61422e565b92915050565b81548190839060ff191660018360038111156107a3576107a361423a565b02179055507f5a7ee3c5ef7f4e3625ee638c3a95481dc4cbfaceda022d1e8fba8ed7fa2208e18160038111156107db576107db61423a565b6040519081526020016105ea565b600080806108026107fa8e83610604565b8d6002610a7b565b9150915060006040518061016001604052808f600060028110610827576108276140c1565b60200201516001600160a01b031681526020018f60016002811061084d5761084d6140c1565b60200201516001600160a01b031681526020018e81526020018d815260200184815260200183815260200160026001600160401b0381111561089157610891613b52565b6040519080825280602002602001820160405280156108ba578160200160208202803683370190505b508152602081018890528651604090910190600019146108db57865161093d565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093d9190614108565b815286516000191460208201526040018660016020020151815250905060006040518060a0016040528089151581526020018d6001600160a01b031681526020018b6001600160a01b031681526020018c81526020018a81525090506109a38282610ddc565b9f9e505050505050505050505050505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1a9190614250565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a57573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614250565b606080826001600160401b03811115610a9657610a96613b52565b604051908082528060200260200182016040528015610abf578160200160208202803683370190505b509150826001600160401b03811115610ada57610ada613b52565b604051908082528060200260200182016040528015610b03578160200160208202803683370190505b50905060005b83811015610c6057848181518110610b2357610b236140c1565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8c919061426d565b610b9790600a614290565b828281518110610ba957610ba96140c1565b602002602001018181525050856001600160a01b031663b3596f07868381518110610bd657610bd66140c1565b60200260200101516040518263ffffffff1660e01b8152600401610bfa919061429f565b602060405180830381865afa158015610c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3b9190614108565b838281518110610c4d57610c4d6140c1565b6020908102919091010152600101610b09565b50935093915050565b600080600073__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528087600001516001600160a01b03166001600160a01b0316815260200187602001516001600160a01b03166001600160a01b03168152508660400151876060015188608001518960a001518a60c001516040518060e001604052808d6101200151610cfe576000610d01565b60015b60ff1681526020018d60e0015181526020018d61010001518152602001600019815260200160008152602001600181526020018d61014001518152506040518863ffffffff1660e01b8152600401610d5f979695949392919061434a565b606060405180830381865af4158015610d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da091906143fc565b50925090508015610dd6576040840151610dbb600183614137565b81518110610dcb57610dcb6140c1565b602002602001015192505b50915091565b60008060008073__$c47fce1b4718dfd79949bdda1ff0df9edc$__632be98102604051806040016040528089600001516001600160a01b03166001600160a01b0316815260200189602001516001600160a01b03166001600160a01b0316815250886040015189606001518a608001518b60a001518c60c001516040518060e001604052808f6101200151610e72576000610e75565b60015b60ff1681526020018f60e0015181526020018f61010001518152602001600019815260200160008152602001600181526020018f61014001518152506040518863ffffffff1660e01b8152600401610ed3979695949392919061434a565b606060405180830381865af4158015610ef0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1491906143fc565b9250925092506000604051806080016040528060028960e001511480610f3c575060e0890151155b15151515815260200160018960e001511480610f5a575060e0890151155b1515815260e0890180516001908114602084015290511460409091015290508315801590610f86575080515b15610fc557610fbd8787610f9b600188614137565b6000610fa860018a614137565b14610fb4576000610fb7565b60015b8761124f565b610100890152505b8115801590610fd5575060208101515b156110e357865160408801516110df91906000610ff3600187614137565b14610fff576000611002565b60015b81518110611012576110126140c1565b6020026020010151896040015160018661102c9190614137565b8151811061103c5761103c6140c1565b60200260200101518a604001516001876110569190614137565b81518110611066576110666140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611099919061429f565b602060405180830381865afa1580156110b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110da9190614108565b6118af565b5050505b8315611244576040810151156111fd576111038787610f9b600188614137565b610100890152506060810151801561111a57508115155b156111f8576000806111518982611132600188614137565b1461113e576000611141565b60015b61114c600188614137565b611a73565b9150915080156111925761118d8961116a600187614137565b6000611177600189614137565b14611183576000611186565b60015b6001612008565b6111f5565b60608901516111a2600186614137565b815181106111b2576111b26140c1565b60200260200101518211156111f5576111f58960006111d2600188614137565b146111de5760006111e1565b60015b6111ec600188614137565b8560001961212e565b50505b611244565b8115801561120d57508661012001515b801561121d575061010087015115155b80156112365750866101000151670de0b6b3a764000014155b156112445761124487612408565b501595945050505050565b600080856000015161126357856060015192505b855160009061127657866040015161127c565b87602001515b905087604001518681518110611294576112946140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016112c7919061429f565b602060405180830381865afa1580156112e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113089190614108565b8411156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906113595760405162461bcd60e51b81526004016104c59190613b3f565b5087604001518681518110611370576113706140c1565b60200260200101516001600160a01b031687602001516001600160a01b0316146040518060400160405280601181526020017054532d323520737761702062792061676760781b815250906113d85760405162461bcd60e51b81526004016104c59190613b3f565b50876060015186815181106113ef576113ef6140c1565b60200260200101518411156118275761142688604001518781518110611417576114176140c1565b602002602001015185836125eb565b600061144e89604001518781518110611441576114416140c1565b602002602001015161265c565b8851909150156114de576114668589606001516126cc565b94506114d68960000151838b604001518a81518110611487576114876140c1565b60200260200101518c604001518a815181106114a5576114a56140c1565b60200260200101518961012c8f606001518e815181106114c7576114c76140c1565b602002602001015160016126e4565b509350611591565b88602001516001600160a01b0316826001600160a01b03161461150457611504826127ef565b600080836001600160a01b03168a60800151604051611523919061442a565b6000604051808303816000865af19150503d8060008114611560576040519150601f19603f3d011682016040523d82523d6000602084013e611565565b606091505b509150915081819061158a5760405162461bcd60e51b81526004016104c59190613b3f565b5086955050505b88600001516001600160a01b031663291f89c48a6040015189815181106115ba576115ba6140c1565b6020026020010151878c604001518a815181106115d9576115d96140c1565b6020026020010151856115fb8f604001518d81518110611441576114416140c1565b6116059190614137565b61012c6040518663ffffffff1660e01b8152600401611628959493929190614446565b602060405180830381865afa158015611645573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611669919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906116b25760405162461bcd60e51b81526004016104c59190613b3f565b507f650da787b25801954b4e03c78b9c6b07fddcbda246347411c49d282c7225f592886060015186836116f48d604001518b81518110611441576114416140c1565b6116fe9190614137565b8c60a001518b81518110611714576117146140c1565b60200260200101518d608001518b81518110611732576117326140c1565b60200260200101518e60a001518c81518110611750576117506140c1565b60200260200101518f608001518e8151811061176e5761176e6140c1565b60200260200101518c6117819190614497565b61178b9190614497565b61179591906144c4565b61179f91906144c4565b868e604001518d815181106117b6576117b66140c1565b60200260200101518f604001518d815181106117d4576117d46140c1565b602090810291909101810151604080519889529188019690965286019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e00160405180910390a1505b8288610120015161183d5788610100015161189f565b306001600160a01b0316634ba31b016040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189f9190614108565b92509250505b9550959350505050565b600080600080856001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016118e1919061429f565b602060405180830381865afa1580156118fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119229190614108565b90506000886001600160a01b031663dd27ede7308a8a60016040518563ffffffff1660e01b815260040161195994939291906144d8565b60408051808303816000875af1158015611977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061199b9190614502565b5090506119b68187106119ae57816119b0565b865b836126cc565b60405163667df24960e01b81523060048201526001600160a01b038a811660248301528981166044830152606482018390529194506000918b169063667df2499060840160408051808303816000875af1158015611a18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3c9190614502565b909650905080861115611a5657611a538187614137565b95505b611a638a8a8a87876128ac565b9550505050509450945094915050565b600080611aaf6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8560a001518581518110611ac557611ac56140c1565b602002602001015186608001518681518110611ae357611ae36140c1565b602002602001015187604001518781518110611b0157611b016140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611b34919061429f565b602060405180830381865afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190614108565b611b7f9190614497565b611b8991906144c4565b604082015260a0860151805185908110611ba557611ba56140c1565b602002602001015186608001518581518110611bc357611bc36140c1565b602002602001015187604001518681518110611be157611be16140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611c14919061429f565b602060405180830381865afa158015611c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c559190614108565b611c5f9190614497565b611c6991906144c4565b60608201528415611c7f57856101000151611c97565b610100860151611c9790670de0b6b3a7640000614137565b81528415611cbc57610100860151611cb790670de0b6b3a7640000614137565b611cc3565b8561010001515b602082015260a0860151805186908110611cdf57611cdf6140c1565b602002602001015186608001518581518110611cfd57611cfd6140c1565b60200260200101518760a001518681518110611d1b57611d1b6140c1565b602002602001015188608001518881518110611d3957611d396140c1565b6020026020010151611d4b9190614497565b611d5d90670de0b6b3a7640000614497565b611d6791906144c4565b611d7191906144c4565b81608001818152505060008087600001516001600160a01b031663e4c2be70308a604001518a81518110611da757611da76140c1565b60200260200101518b604001518a81518110611dc557611dc56140c1565b602002602001015160016040518563ffffffff1660e01b8152600401611dee94939291906144d8565b6040805180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614502565b9150915081600003611f0e5760208301518351600091611e4d91614526565b845160608601516040870151611e639190614526565b611e6d9190614497565b611e7791906144c4565b9050836040015181118015611f0657508860a001518881518110611e9d57611e9d6140c1565b602002602001015189608001518981518110611ebb57611ebb6140c1565b60200260200101518a606001518a81518110611ed957611ed96140c1565b6020026020010151611eeb9190614497565b611ef591906144c4565b6040850151611f049083614137565b115b945050611faa565b8260000151670de0b6b3a7640000838386608001518760200151611f329190614497565b611f3c9190614497565b611f4691906144c4565b611f5091906144c4565b611f5a9190614539565b83604001518460200151611f6e9190614497565b60608501518551611f7f9190614497565b611f899190614561565b611f939190614588565b60a0840181905260001215611faa578260a0015194505b87608001518681518110611fc057611fc06140c1565b60200260200101518860a001518781518110611fde57611fde6140c1565b602002602001015186611ff19190614497565b611ffb91906144c4565b9450505050935093915050565b61212884848487604001518781518110612024576120246140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612057919061429f565b602060405180830381865afa158015612074573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120989190614108565b886040015187815181106120ae576120ae6140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120e1919061429f565b602060405180830381865afa1580156120fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121229190614108565b86612a95565b50505050565b600085604001518481518110612146576121466140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612179919061429f565b602060405180830381865afa158015612196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ba9190614108565b90506122068660000151876040015187815181106121da576121da6140c1565b6020026020010151886040015187815181106121f8576121f86140c1565b6020026020010151866118af565b505050600086604001518581518110612221576122216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612254919061429f565b602060405180830381865afa158015612271573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122959190614108565b905060008183116122a75760006122b1565b6122b18284614137565b905084811080156122e95750876060015186815181106122d3576122d36140c1565b602002602001015181866122e79190614137565b115b156123fe57600088600001516001600160a01b031663e4c2be70308b604001518b8151811061231a5761231a6140c1565b60200260200101518c604001518b81518110612338576123386140c1565b602002602001015160016040518563ffffffff1660e01b815260040161236194939291906144d8565b6040805180830381865afa15801561237d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a19190614502565b509050886060015187815181106123ba576123ba6140c1565b6020026020010151811180156123cf57508481105b156123ef576123ea8989896123e4868b614137565b8561212e565b6123fc565b6123fc89888a6000612008565b505b5050505050505050565b60008160400151600081518110612421576124216140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612454919061429f565b602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614108565b9050600082604001516001815181106124b0576124b06140c1565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016124e3919061429f565b602060405180830381865afa158015612500573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125249190614108565b905060008061254785608001518660a00151868689610100015160006001612db8565b915091508184111561259a57846060015160008151811061256a5761256a6140c1565b6020026020010151828561257e9190614137565b111561259557612595856000600187876001612a95565b6125e4565b808311156125e45784606001516000815181106125b9576125b96140c1565b602002602001015181846125cd9190614137565b11156125e4576125e4856001600086886001612a95565b5050505050565b60405163095ea7b360e01b81526001600160a01b0384169063095ea7b3906126199084908690600401613ed7565b6020604051808303816000875af1158015612638573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612128919061447a565b6040516370a0823160e01b81526000906001600160a01b038316906370a082319061268b90309060040161429f565b602060405180830381865afa1580156126a8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077f9190614108565b60008183106126db57816126dd565b825b9392505050565b6000808386116126f9575060009050806127e2565b604051633744088160e11b81526001600160a01b0389811660048301528881166024830152600091908b1690636e88110290604401600060405180830381865afa15801561274b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261277391908101906145fb565b50805160408051808201909152601a81527f54532d3135204e6f206c69717569646174696f6e20726f75746500000000000060208201529192506127ca5760405162461bcd60e51b81526004016104c59190613b3f565b50866127dc8c838d8d8d8d8d8c612f47565b92509250505b9850989650505050505050565b6001600160a01b038116731111111254eeb25477b68fb85ed929f73a960582148061283657506001600160a01b038116736352a56caadc4f1e25cd6c75970fa768a3304e64145b8061285d57506001600160a01b038116736dd434082eab5cd134b33719ec1ff05fe985b97b145b604051806040016040528060148152602001732821299698902ab735b737bbb7103937baba32b960611b815250906128a85760405162461bcd60e51b81526004016104c59190613b3f565b5050565b600080606484106118a5576128cb6001600160a01b0386168886613225565b6040516314b685e960e21b81526001600160a01b038781166004830152868116602483015260448201869052306064830152600091908916906352da17a4906084016080604051808303816000875af115801561292c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129509190614714565b5050604080516001600160a01b03808c1682528a1660208201529081018890523060608201526080810183905260a0810182905291945091507f1d1ba11e7ca20f5dc77d8cfd75b68d11520677808f89f6ba0f0e50dc52c450129060c00160405180910390a16040516370a0823160e01b81526000906001600160a01b038816906370a08231906129e590309060040161429f565b602060405180830381865afa158015612a02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a269190614108565b9050808511612a36576000612a40565b612a408186614137565b60408051808201909152600f81526e53423a2057726f6e672076616c756560881b60208201529093508215612a885760405162461bcd60e51b81526004016104c59190613b3f565b5050509550959350505050565b8015612bac57600086600001516001600160a01b031663e4c2be703089604001518881518110612ac757612ac76140c1565b60200260200101518a604001518a81518110612ae557612ae56140c1565b602002602001015160006040518563ffffffff1660e01b8152600401612b0e94939291906144d8565b6040805180830381865afa158015612b2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4e9190614502565b509050606481106040518060400160405280601a81526020017f54532d3239206f70706f7369746520646562742065786973747300000000000081525090612ba95760405162461bcd60e51b81526004016104c59190613b3f565b50505b600060405180610160016040528060405180604001604052808a600001516001600160a01b031681526020018a602001516001600160a01b0316815250815260200188604001518881518110612c0457612c046140c1565b60200260200101516001600160a01b0316815260200188604001518781518110612c3057612c306140c1565b60200260200101516001600160a01b0316815260200160008814612c5957886101000151612c71565b610100890151612c7190670de0b6b3a7640000614137565b81526020018715612c9957610100890151612c9490670de0b6b3a7640000614137565b612ca0565b8861010001515b81526020018860a001518781518110612cbb57612cbb6140c1565b602002602001015189608001518981518110612cd957612cd96140c1565b60200260200101518a60a001518a81518110612cf757612cf76140c1565b60200260200101518b608001518a81518110612d1557612d156140c1565b6020026020010151670de0b6b3a7640000612d309190614497565b612d3a9190614497565b612d4491906144c4565b612d4e91906144c4565b815260200188606001518881518110612d6957612d696140c1565b6020026020010151815260200160008152602001600081526020018781526020018681525090506123fc8160405180604001604052808a6080015181526020018a60a001518152508686613280565b6000806000888581518110612dcf57612dcf6140c1565b60200260200101518a8681518110612de957612de96140c1565b602002602001015189612dfc9190614497565b612e0691906144c4565b90506000898581518110612e1c57612e1c6140c1565b60200260200101518b8681518110612e3657612e366140c1565b602002602001015189612e499190614497565b612e5391906144c4565b90508615612e8857670de0b6b3a764000087612e6f8385614526565b612e799190614497565b612e8391906144c4565b612e8b565b60005b92508a8681518110612e9f57612e9f6140c1565b60200260200101518a8781518110612eb957612eb96140c1565b6020026020010151848385612ece9190614526565b612ed89190614137565b612ee29190614497565b612eec91906144c4565b93508a8581518110612f0057612f006140c1565b60200260200101518a8681518110612f1a57612f1a6140c1565b602002602001015184612f2d9190614497565b612f3791906144c4565b9250505097509795505050505050565b6000612f548685896133ed565b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190612f8390309060040161429f565b602060405180830381865afa158015612fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc49190614108565b6040516310fe133960e31b81529091506001600160a01b038916906387f099c890612ff7908c908990899060040161474a565b600060405180830381600087803b15801561301157600080fd5b505af1158015613025573d6000803e3d6000fd5b50506040516370a0823160e01b8152600092506001600160a01b03891691506370a082319061305890309060040161429f565b602060405180830381865afa158015613075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130999190614108565b90508181116040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b815250906130eb5760405162461bcd60e51b81526004016104c59190613b3f565b506130f68282614137565b925083806131745750604051630a47e27160e21b81526001600160a01b038c169063291f89c490613133908b908a908c9089908c90600401614446565b602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613174919061447a565b604051806040016040528060128152602001711514cb4c4d881c1c9a58d9481a5b5c1858dd60721b815250906131bd5760405162461bcd60e51b81526004016104c59190613b3f565b50604080516001600160a01b03808b1682528916602082015290810187905260608101879052608081018490527f5a821a618ddb1a1fd304234a69c9d7f20c129d122fcf35593d13a071926643079060a00160405180910390a1505098975050505050505050565b61327b8363a9059cbb60e01b8484604051602401613244929190613ed7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613498565b505050565b6000808560e00151600014806132995750610100860151155b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906132e35760405162461bcd60e51b81526004016104c59190613b3f565b506101008601511561335e57856101000151831061331f576133168685886101000151866133119190614137565b61356a565b915091506133e4565b600061333d878787878b61010001516133389190614137565b613703565b5090506133548761334e8388614137565b8661356a565b92509250506133e4565b60e0860151156133d9578560e001518410156040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906133be5760405162461bcd60e51b81526004016104c59190613b3f565b50613316868760e00151866133d39190614137565b8561356a565b61331686858561356a565b94509492505050565b604051636eb1769f60e11b81523060048201526001600160a01b03828116602483015283919085169063dd62ed3e90604401602060405180830381865afa15801561343c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134609190614108565b101561327b5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390612619908490600160ff1b90600401613ed7565b60006134ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661390c9092919063ffffffff16565b80519091501561327b578080602001905181019061350b919061447a565b61327b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016104c5565b60608381015160808086015160408051600160208201528082019490945283850191909152805180840390940184529101905260009081908190841561363a57670de0b6b3a7640000876080015188606001518960a00151886135cd9190614497565b6135d79190614497565b6135e191906144c4565b6135eb91906144c4565b9150858211156040518060400160405280601081526020016f54532d392077726f6e672076616c756560801b815250906136385760405162461bcd60e51b81526004016104c59190613b3f565b505b60208701516136559061364d8489614137565b8951516133ed565b73__$e930d50fb5f4f1298547dbcb2bb0591990$__63ca27d10d886000015160000151838a602001518b60400151878c61368f9190614137565b8d60c001516040518763ffffffff1660e01b81526004016136b5969594939291906147cc565b6040805180830381865af41580156136d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136f59190614502565b935093505050935093915050565b6000806000856020015187610140015181518110613723576137236140c1565b6020026020010151866000015188610120015181518110613746576137466140c1565b6020026020010151876020015189610120015181518110613769576137696140c1565b602002602001015188600001518a61014001518151811061378c5761378c6140c1565b60200260200101518761379f9190614497565b6137a99190614497565b6137b391906144c4565b6137bd91906144c4565b9050620186a06137cf61012c82614526565b6137d99083614497565b6137e391906144c4565b90508085116040518060400160405280601781526020017654532d37206e6f7420656e6f7567682062616c616e636560481b815250906138365760405162461bcd60e51b81526004016104c59190613b3f565b5086518051602091820151918901516040808b015160c08c01519151637de8f56960e01b81526001600160a01b03948516600482015294841660248601529183166044850152911660648301526084820183905261012c60a483015260c4820152600060e482015273__$e930d50fb5f4f1298547dbcb2bb0591990$__90637de8f56990610104016040805180830381865af41580156138da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fe9190614502565b909890975095505050505050565b606061391b8484600085613923565b949350505050565b6060824710156139845760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016104c5565b600080866001600160a01b031685876040516139a0919061442a565b60006040518083038185875af1925050503d80600081146139dd576040519150601f19603f3d011682016040523d82523d6000602084013e6139e2565b606091505b50915091506139f3878383876139fe565b979650505050505050565b60608315613a6d578251600003613a66576001600160a01b0385163b613a665760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104c5565b508161391b565b61391b8383815115613a825781518083602001fd5b8060405162461bcd60e51b81526004016104c59190613b3f565b8260048101928215613aca579160200282015b82811115613aca578251825591602001919060010190613aaf565b50613ad6929150613ada565b5090565b5b80821115613ad65760008155600101613adb565b60005b83811015613b0a578181015183820152602001613af2565b50506000910152565b60008151808452613b2b816020860160208601613aef565b601f01601f19169290920160200192915050565b6020815260006126dd6020830184613b13565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613b8a57613b8a613b52565b60405290565b604080519081016001600160401b0381118282101715613b8a57613b8a613b52565b604051601f8201601f191681016001600160401b0381118282101715613bda57613bda613b52565b604052919050565b60008060a08385031215613bf557600080fd5b82359150602084603f850112613c0a57600080fd5b604051608081018181106001600160401b0382111715613c2c57613c2c613b52565b6040528060a0860187811115613c4157600080fd5b8387015b81811015613c5c5780358352918401918401613c45565b50505080925050509250929050565b6001600160a01b0381168114613c8057600080fd5b50565b8035613c8e81613c6b565b919050565b600082601f830112613ca457600080fd5b613cac613b90565b806040840185811115613cbe57600080fd5b845b81811015613ce1578035613cd381613c6b565b845260209384019301613cc0565b509095945050505050565b60006001600160401b03821115613d0557613d05613b52565b5060051b60200190565b600082601f830112613d2057600080fd5b81356020613d35613d3083613cec565b613bb2565b82815260059290921b84018101918181019086841115613d5457600080fd5b8286015b84811015613d78578035613d6b81613c6b565b8352918301918301613d58565b509695505050505050565b600082601f830112613d9457600080fd5b81356020613da4613d3083613cec565b82815260059290921b84018101918181019086841115613dc357600080fd5b8286015b84811015613d785780358352918301918301613dc7565b600082601f830112613def57600080fd5b613df7613b90565b806040840185811115613e0957600080fd5b845b81811015613ce1578035845260209384019301613e0b565b6000806000806000806101008789031215613e3d57600080fd5b613e478888613c93565b955060408701356001600160401b0380821115613e6357600080fd5b613e6f8a838b01613d0f565b96506060890135915080821115613e8557600080fd5b613e918a838b01613d83565b95506080890135915080821115613ea757600080fd5b50613eb489828a01613d83565b93505060a08701359150613ecb8860c08901613dde565b90509295509295509295565b6001600160a01b03929092168252602082015260400190565b600060208284031215613f0257600080fd5b5035919050565b60008060408385031215613f1c57600080fd5b82359150602083013560048110613f3257600080fd5b809150509250929050565b60006001600160401b03821115613f5657613f56613b52565b50601f01601f191660200190565b600082601f830112613f7557600080fd5b8135613f83613d3082613f3d565b818152846020838601011115613f9857600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114613c8057600080fd5b8035613c8e81613fb5565b6000806000806000806000806000806101808b8d031215613fee57600080fd5b613ff88c8c613c93565b995060408b01356001600160401b038082111561401457600080fd5b6140208e838f01613d0f565b9a5060608d013591508082111561403657600080fd5b6140428e838f01613d83565b995061405060808e01613c83565b985060a08d0135975061406560c08e01613c83565b965060e08d013591508082111561407b57600080fd5b506140888d828e01613f64565b9450506140986101008c01613fc3565b92506101208b013591506140b08c6101408d01613dde565b90509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b60808101818360005b60048110156140ff5781518352602092830192909101906001016140e0565b50505092915050565b60006020828403121561411a57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561077f5761077f614121565b600181815b8085111561418557816000190482111561416b5761416b614121565b8085161561417857918102915b93841c939080029061414f565b509250929050565b60008261419c5750600161077f565b816141a95750600061077f565b81600181146141bf57600281146141c9576141e5565b600191505061077f565b60ff8411156141da576141da614121565b50506001821b61077f565b5060208310610133831016604e8410600b8410161715614208575081810a61077f565b614212838361414a565b806000190482111561422657614226614121565b029392505050565b60006126dd838361418d565b634e487b7160e01b600052602160045260246000fd5b60006020828403121561426257600080fd5b81516126dd81613c6b565b60006020828403121561427f57600080fd5b815160ff811681146126dd57600080fd5b60006126dd60ff84168361418d565b6001600160a01b0391909116815260200190565b600081518084526020808501945080840160005b838110156142ec5781516001600160a01b0316875295820195908201906001016142c7565b509495945050505050565b600081518084526020808501945080840160005b838110156142ec5781518752958201959082019060010161430b565b8060005b600781101561212857815184526020938401939091019060010161432b565b60006101c0828a835b600281101561437b5781516001600160a01b0316835260209283019290910190600101614353565b5050508060408401526143908184018a6142b3565b905082810360608401526143a481896142f7565b905082810360808401526143b881886142f7565b905082810360a08401526143cc81876142f7565b905082810360c08401526143e081866142f7565b9150506143f060e0830184614327565b98975050505050505050565b60008060006060848603121561441157600080fd5b8351925060208401519150604084015190509250925092565b6000825161443c818460208701613aef565b9190910192915050565b6001600160a01b03958616815260208101949094529190931660408301526060820192909252608081019190915260a00190565b60006020828403121561448c57600080fd5b81516126dd81613fb5565b808202811582820484141761077f5761077f614121565b634e487b7160e01b600052601260045260246000fd5b6000826144d3576144d36144ae565b500490565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b6000806040838503121561451557600080fd5b505080516020909101519092909150565b8082018082111561077f5761077f614121565b808201828112600083128015821682158216171561455957614559614121565b505092915050565b818103600083128015838313168383128216171561458157614581614121565b5092915050565b600082614597576145976144ae565b600160ff1b8214600019841416156145b1576145b1614121565b500590565b600082601f8301126145c757600080fd5b81516145d5613d3082613f3d565b8181528460208386010111156145ea57600080fd5b61391b826020830160208701613aef565b600080604080848603121561460f57600080fd5b83516001600160401b038082111561462657600080fd5b818601915086601f83011261463a57600080fd5b8151602061464a613d3083613cec565b82815260079290921b8401810191818101908a84111561466957600080fd5b948201945b838610156146e3576080868c0312156146875760008081fd5b61468f613b68565b865161469a81613c6b565b8152868401516146a981613c6b565b81850152868801516146ba81613c6b565b818901526060878101516146cd81613c6b565b908201528252608095909501949082019061466e565b918901519197509094505050808311156146fc57600080fd5b505061470a858286016145b6565b9150509250929050565b6000806000806080858703121561472a57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6060808252845182820181905260009190608090818501906020808a01865b838110156147b157815180516001600160a01b039081168752848201518116858801526040808301518216908801529088015116878601529385019390820190600101614769565b50508601979097526040909401949094525090949350505050565b600060018060a01b03808916835260c060208401526147ee60c0840189613b13565b9681166040840152949094166060820152608081019290925260a090910152509291505056fe5042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a26469706673582212207f7752bf16958260345ca337e20a634d0ac44946dd9dffcf9ee3083394e513cf64736f6c63430008110033", "libraries": { - "ConverterStrategyBaseLib": "0x0Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1", + "ConverterStrategyBaseLib": "0x2af59Be93d77B391Fea20322407fE46907Bf9D0E", "IterationPlanLib": "0x0118015B5D5F7f104292DB79Ae47AA0e962A09be" }, "devdoc": { diff --git a/deployments/matic/PairBasedStrategyLogicLib.json b/deployments/matic/PairBasedStrategyLogicLib.json index dd5f82d4..ef77ddc4 100644 --- a/deployments/matic/PairBasedStrategyLogicLib.json +++ b/deployments/matic/PairBasedStrategyLogicLib.json @@ -1,5 +1,5 @@ { - "address": "0xB2dD88095aFe40481C4969f8761DE3D6BC08D222", + "address": "0x06901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39", "abi": [ { "inputs": [ @@ -36,48 +36,48 @@ "type": "function" } ], - "transactionHash": "0xc66c87e64c680e0fe72b98b8fb50898de568abf448208d9a14ff2c1fcbee1d2f", + "transactionHash": "0xb9a8eb9007c263f34aefe8bdfd68e36e1a4f2c352f629111d24e308973f003ae", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0xB2dD88095aFe40481C4969f8761DE3D6BC08D222", - "transactionIndex": 120, - "gasUsed": "2198216", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0xd55da65525a546f2b3232672c0cb73999ddadb5471f2e8a6735af03c6a4feb5c", - "transactionHash": "0xc66c87e64c680e0fe72b98b8fb50898de568abf448208d9a14ff2c1fcbee1d2f", + "contractAddress": "0x06901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39", + "transactionIndex": 30, + "gasUsed": "2198228", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000400000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0xdda55666a86dbdb64dc48fbf33056b7646345b5770dca7440a3ac160330accb5", + "transactionHash": "0xb9a8eb9007c263f34aefe8bdfd68e36e1a4f2c352f629111d24e308973f003ae", "logs": [ { - "transactionIndex": 120, - "blockNumber": 54803198, - "transactionHash": "0xc66c87e64c680e0fe72b98b8fb50898de568abf448208d9a14ff2c1fcbee1d2f", + "transactionIndex": 30, + "blockNumber": 55572321, + "transactionHash": "0xb9a8eb9007c263f34aefe8bdfd68e36e1a4f2c352f629111d24e308973f003ae", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x0000000000000000000000007c7379531b2aee82e4ca06d4175d13b9cbeafd49" ], - "data": "0x000000000000000000000000000000000000000000000000000bb6e611bab80000000000000000000000000000000000000000000000000269433731d4caa003000000000000000000000000000000000000000000002435f44a25471d70e1d60000000000000000000000000000000000000000000000026937804bc30fe803000000000000000000000000000000000000000000002435f455dc2d2f2b99d6", - "logIndex": 404, - "blockHash": "0xd55da65525a546f2b3232672c0cb73999ddadb5471f2e8a6735af03c6a4feb5c" + "data": "0x000000000000000000000000000000000000000000000000014b7caa74813bc0000000000000000000000000000000000000000000000001dafe95f4070db30400000000000000000000000000000000000000000002e457e923f31aad77cc33000000000000000000000000000000000000000000000001d9b31949928c774400000000000000000000000000000000000000000002e457ea6f6fc521f907f3", + "logIndex": 128, + "blockHash": "0xdda55666a86dbdb64dc48fbf33056b7646345b5770dca7440a3ac160330accb5" } ], - "blockNumber": 54803198, - "cumulativeGasUsed": "16197743", + "blockNumber": 55572321, + "cumulativeGasUsed": "7028879", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 13, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickRange\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"calcTickRange\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"_beforeDeposit(ITetuConverter,uint256,address,address,uint256,mapping(address => uint256) storage)\":{\"params\":{\"amount_\":\"Amount of tokenA\",\"liquidationThresholds\":\"Dust-thresholds for the tokens A and B\",\"prop0\":\"Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\",\"tokenA\":\"Underlying\",\"tokenB\":\"Not-underlying\"},\"returns\":{\"tokenAmounts\":\"Amounts of token A and B to be deposited, [A, B]\"}},\"getDefaultState(PairBasedStrategyLogicLib.PairState storage)\":{\"returns\":{\"addr\":\"[tokenA, tokenB, pool, profitHolder]\",\"boolValues\":\"[isStablePool, depositorSwapTokens]\",\"nums\":\"[totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter,int24,uint256)\":{\"returns\":{\"needRebalance\":\"A boolean indicating if {rebalanceNoSwaps} should be called\"}},\"quoteWithdrawByAgg(PairBasedStrategyLogicLib.PairState storage,bytes,uint256[],address,ITetuConverter,mapping(address => uint256) storage)\":{\"params\":{\"amounts_\":\"Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\"}},\"setInitialDepositorValues(PairBasedStrategyLogicLib.PairState storage,address[4],int24[4],bool,uint256[4])\":{\"params\":{\"addr\":\"[pool, asset, pool.token0(), pool.token1()] asset: Underlying asset of the depositor.\",\"fuseThresholds\":\"Fuse thresholds for tokens (stable pool only)\",\"pairState\":\"Depositor storage state struct to be initialized\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"withdrawByAggStep(address[5],uint256[4],bytes,bytes,address[2],mapping(address => uint256) storage)\":{\"params\":{\"addr_\":\"[tokenToSwap, aggregator, controller, converter, splitter]\",\"tokens\":\"[underlying, not-underlying] (values been read from pairBase)\",\"values_\":\"[amountToSwap_, profitToCover, oldTotalAssets, not used here]\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to proper proportions\",\"tokenAmounts\":\"Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"_beforeDeposit(ITetuConverter,uint256,address,address,uint256,mapping(address => uint256) storage)\":{\"notice\":\"Prepare array of amounts ready to deposit, borrow missed amounts\"},\"getDefaultState(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Returns the current state of the contract\"},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter,int24,uint256)\":{\"notice\":\"Determine if the strategy needs to be rebalanced.\"},\"quoteWithdrawByAgg(PairBasedStrategyLogicLib.PairState storage,bytes,uint256[],address,ITetuConverter,mapping(address => uint256) storage)\":{\"notice\":\"Get info about a swap required by next call of {withdrawByAggStep} within the given plan\"},\"setInitialDepositorValues(PairBasedStrategyLogicLib.PairState storage,address[4],int24[4],bool,uint256[4])\":{\"notice\":\"Set the initial values to PairState instance\"},\"withdrawByAggStep(address[5],uint256[4],bytes,bytes,address[2],mapping(address => uint256) storage)\":{\"notice\":\"Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\"}},\"notice\":\"Library for the UniV3-like strategies with two tokens in the pool\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":\"PairBasedStrategyLogicLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x6126cb61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c80636e81b629116100655780636e81b62914610150578063b8b4a44914610173578063bd13c52914610193578063cd8e20e7146101c257600080fd5b80631c2040d5146100975780634aa00915146100cd57806350d2e0ba146100ef57806351265e891461012e575b600080fd5b8180156100a357600080fd5b506100b76100b2366004611a86565b6101ef565b6040516100c49190611b26565b60405180910390f35b8180156100d957600080fd5b506100ed6100e8366004611b47565b61031c565b005b8180156100fb57600080fd5b5061010f61010a366004611c91565b6103a9565b604080516001600160a01b0390931683526020830191909152016100c4565b61014161013c366004611d95565b610504565b6040516100c493929190611e13565b61016361015e366004611e39565b6106ba565b6040516100c49493929190611e8b565b81801561017f57600080fd5b506100ed61018e366004611f44565b610a7d565b81801561019f57600080fd5b506101b36101ae366004611faa565b610dc8565b6040516100c49392919061209b565b6101d56101d03660046120c6565b611293565b60408051600293840b81529190920b6020820152016100c4565b606073d84c6293b2E190DDd7Ea7F6E00396A840294BDcE634b4bd6f7888860405180604001604052808a6001600160a01b03166001600160a01b03168152602001896001600160a01b03166001600160a01b0316815250604051806040016040528061027e8960008e6001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b81526001600160a01b038b16600090815260208a81526040909120549101906102a690611358565b815250886040518663ffffffff1660e01b81526004016102ca959493929190612158565b600060405180830381865af41580156102e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261030f91908101906121ff565b90505b9695505050505050565b60008215610395576040516335ffd9a360e11b815273E5779B35180c1048562c733A7E62f8Fe1d253C4190636bffb346906103609060058801908690600401612234565b60006040518083038186803b15801561037857600080fd5b505af415801561038c573d6000803e3d6000fd5b50505050600190505b80156103a3576000600e8501555b50505050565b6000806103b46119c4565b6040805180820190915260028a01546001600160a01b03908116825260038b01541660208201526103e9908290868b8a611371565b73E5779B35180c1048562c733A7E62f8Fe1d253C416314ad109e6040518060400160405280886001600160a01b03166001600160a01b031681526020016104338560200151611557565b6001600160a01b0316905283516040808601516060870151825180840184526080890151815260a0890151602082015292516001600160e01b031960e088901b1681526104879594938f9291600401612248565b6040805180830381865af41580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c791906122b2565b909350915081156104f857620186a06104e16064846122f6565b6104eb9190612323565b6104f59083612337565b91505b50965096945050505050565b60008060008660030160149054906101000a900460ff16156106a35760028701546003880154604051637fd6c0a160e01b81526001600160a01b03808a16600483015292831660248201529116604482015260009073C92346a144fa75b45b0eDAe966FEAA0E30C82c5590637fd6c0a190606401602060405180830381865af4158015610595573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b9919061234a565b604080516060810190915260058a01805492935061067492829060ff1660038111156105e7576105e7611ddb565b60038111156105f8576105f8611ddb565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161061857505050918352505060408051608081019182905260209092019190600584019060049082845b8154815260200190600101908083116106515750505050508152505082876115bb565b9093509150828061069b575061068982611733565b15801561069b575061069b8887611750565b9350506106b0565b6106ad8786611750565b92505b9450945094915050565b60408051600480825260a082019092526060918291829182919060208201608080368337505060408051600480825260a08201909252929650905060208201608080368337505060408051600d8082526101c082019092529295509050602082016101a0803683375050604080516002808252606082018352939550929150602083019080368337505050600286015485519192506001600160a01b031690859060009061076a5761076a612363565b6001600160a01b039283166020918202929092010152600386015485519116908590600190811061079d5761079d612363565b6001600160a01b03928316602091820292909201015285548551911690859060029081106107cd576107cd612363565b6001600160a01b039283166020918202929092010152600186015485519116908590600390811061080057610800612363565b60200260200101906001600160a01b031690816001600160a01b0316815250508460030160169054906101000a900460020b8360008151811061084557610845612363565b600292830b602091820292909201015260038601548451600160c81b90910490910b908490600190811061087b5761087b612363565b600292830b602091820292909201015260038601548451600160e01b909104820b91859181106108ad576108ad612363565b600292830b602091820292909201015260048601548451910b90849060039081106108da576108da612363565b602002602001019060020b908160020b815250508460040160039054906101000a90046001600160801b03166001600160801b03168260008151811061092257610922612363565b6020908102919091010152600585015460ff16600381111561094657610946611ddb565b8260018151811061095957610959612363565b60200260200101818152505084600e01548260038151811061097d5761097d612363565b60200260200101818152505060005b60048110156109e3576006860181600481106109aa576109aa612363565b0154836109b8836004612379565b815181106109c8576109c8612363565b60209081029190910101526109dc8161238c565b905061098c565b5084600f015482600c815181106109fc576109fc612363565b6020026020010181815250508460030160149054906101000a900460ff1681600081518110610a2d57610a2d612363565b6020026020010190151590811515815250508460030160159054906101000a900460ff1681600181518110610a6457610a64612363565b6020026020010190151590811515815250509193509193565b610a8a60208501856123a5565b85546001600160a01b0319166001600160a01b03919091161785556000610ab760408601602087016123a5565b90506000610acb60608701604088016123a5565b90506000610adf60808801606089016123a5565b9050610aee60208701876123c2565b60038901805462ffffff92909216600160b01b0262ffffff60b01b19909216919091179055610b2360408701602088016123c2565b60038901805462ffffff92909216600160c81b0262ffffff60c81b19909216919091179055610b5860608701604088016123c2565b60038901805462ffffff92909216600160e01b0262ffffff60e01b19909216919091179055610b8d60808701606088016123c2565b60048901805462ffffff191662ffffff929092169190911790556001600160a01b038281169084161480610bd25750806001600160a01b0316836001600160a01b0316145b60405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525090610c275760405162461bcd60e51b8152600401610c1e9190612423565b60405180910390fd5b50816001600160a01b0316836001600160a01b031603610c84576002880180546001600160a01b038085166001600160a01b031990921691909117909155600389018054600161ff0160a01b031916918316919091179055610cc9565b6002880180546001600160a01b038084166001600160a01b031990921691909117909155600389018054600161ff0160a01b03191691841691909117600160a81b1790555b8415610dbe5760038801805460ff60a01b1916600160a01b1790556040516335ffd9a360e11b815273E5779B35180c1048562c733A7E62f8Fe1d253C4190636bffb34690610d219060058c0190600190600401612234565b60006040518083038186803b158015610d3957600080fd5b505af4158015610d4d573d6000803e3d6000fd5b5050604051630593c4c960e01b815273E5779B35180c1048562c733A7E62f8Fe1d253C419250630593c4c99150610d8d9060058c01908890600401612436565b60006040518083038186803b158015610da557600080fd5b505af4158015610db9573d6000803e3d6000fd5b505050505b5050505050505050565b600060606000610dd6611a03565b610de360208b018b6123a5565b6001600160a01b03166020820152896001602002016020810190610e0791906123a5565b6001600160a01b03166040820152896002602002016020810190610e2b91906123a5565b6001600160a01b03166060820152896003602002016020810190610e4f91906123a5565b6001600160a01b03166080820152896004602002016020810190610e7391906123a5565b6001600160a01b031660a0820152883560c0820152602089013560e0820152604089013561010082015280516060820151610eb49190889088908b90611371565b73E5779B35180c1048562c733A7E62f8Fe1d253C41637545be26604051806040016040528084608001516001600160a01b03166001600160a01b03168152602001610f06856000015160200151611557565b6001600160a01b03166001600160a01b031681525083600001516000015184600001516040015185602001518660c0015187604001518f60006001600160a01b03168a604001516001600160a01b0316148a600001516060015160405180604001604052808d600001516080015181526020018d6000015160a001518152506040518b63ffffffff1660e01b8152600401610faa9a9998979695949392919061244c565b602060405180830381865af4158015610fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610feb91906124e3565b93508060e0015160001461115857805151805173C92346a144fa75b45b0eDAe966FEAA0E30C82c559163890ffb849160009061102957611029612363565b60200260200101518360e001518460a0015185610100015186600001516000015160008151811061105c5761105c612363565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061234a565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af4158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190612500565b50505b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563ac2a37d6826080015183610100015184600001516000015160008151811061119857611198612363565b60200260200101518560000151600001516001815181106111bb576111bb612363565b602002602001015160405180604001604052808860000151604001516000815181106111e9576111e9612363565b6020026020010151815260200188600001516040015160018151811061121157611211612363565b60200260200101518152506040518663ffffffff1660e01b815260040161123c959493929190612524565b600060405180830381865af4158015611259573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112819190810190612558565b949b949a509850929650505050505050565b60008060008560020b1280156112c45750600285900b836112b4818861259f565b6112be91906125d9565b60020b14155b156112fc57826001816112d78789612600565b6112e1919061259f565b6112eb9190612600565b6112f591906125d9565b915061131f565b82806113088688612600565b611312919061259f565b61131c91906125d9565b91505b8360020b600014611344576113358460026125d9565b61133f9083612625565b61134e565b61134e8383612625565b9050935093915050565b60008115611366578161136b565b620186a05b92915050565b6001600160a01b0381166020860181905260405163124fdbb760e21b815260048101919091527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063493f6edc9060240160006040518083038186803b1580156113ce57600080fd5b505af41580156113e2573d6000803e3d6000fd5b505050506113ef82611791565b6060860181905261140090836117b8565b60a0870152608086015260408051600280825260608201835290916020830190803683375050508086528451602086015182519192909160009061144657611446612363565b60200260200101876000015160018151811061146457611464612363565b6001600160a01b0393841660209182029290920101529116905260408051600280825260608201909252908160200160208202803683375050506040860152845180516114ed9185916000919082906114bf576114bf612363565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b856040015160008151811061150457611504612363565b60200260200101818152505061152d83600087600001516001815181106114bf576114bf612363565b856040015160018151811061154457611544612363565b6020026020010181815250505050505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b919061264a565b60008080855160038111156115d2576115d2611ddb565b14611718576001855160038111156115ec576115ec611ddb565b0361164c576020850151518411158061160a57506020850151518311155b1561161b5750600190506002611718565b6020850151604001518410158061163a57506020850151604001518310155b1561164757506001905060035b611718565b60028551600381111561166157611661611ddb565b036116c15760208581015101518410801590611684575060208581015101518310155b156116475760208501516040015160019250841015806116ac57506020850151604001518310155b156116b957506003611718565b506001611718565b60208501516060015184118015906116e157506020850151606001518311155b156117185760208581015101516001925084111580611707575060208581015101518311155b1561171457506002611718565b5060015b8182611725578551611727565b815b91509150935093915050565b6000600182600381111561174957611749611ddb565b1192915050565b6003820154600483015460009161178a918491600160c81b8104600290810b92600160e01b8304820b92600160b01b9004820b910b61191a565b9392505050565b600081516000036117a457506000919050565b8180602001905181019061136b919061234a565b6000808315806117c85750600284145b1561184c57828060200190518101906117e19190612500565b925050670de0b6b3a7640000821115806117fc575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118465760405162461bcd60e51b8152600401610c1e9190612423565b50611913565b60408051808201909152601081526f54532d392077726f6e672076616c756560801b6020820152600185146118945760405162461bcd60e51b8152600401610c1e9190612423565b50828060200190518101906118a99190612667565b909350915050670de0b6b3a7640000821115806118c7575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906119115760405162461bcd60e51b8152600401610c1e9190612423565b505b9250929050565b6000600283900b61192b8686612600565b60020b03611954578460020b8660020b128061194d57508360020b8660020b12155b90506119bb565b600060026119628787612600565b61196c919061259f565b9050600061197a8288612625565b90508060020b8860020b136119a157600284900b6119988983612600565b60020b136119b6565b600284900b6119b0828a612600565b60020b12155b925050505b95945050505050565b6040518060c001604052806060815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b604051806101400160405280611a176119c4565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101209091015290565b6001600160a01b0381168114611a7357600080fd5b50565b8035611a8181611a5e565b919050565b60008060008060008060c08789031215611a9f57600080fd5b8635611aaa81611a5e565b9550602087013594506040870135611ac181611a5e565b93506060870135611ad181611a5e565b9598949750929560808101359460a0909101359350915050565b600081518084526020808501945080840160005b83811015611b1b57815187529582019590820190600101611aff565b509495945050505050565b60208152600061178a6020830184611aeb565b8015158114611a7357600080fd5b600080600060608486031215611b5c57600080fd5b833592506020840135611b6e81611b39565b9150604084013560048110611b8257600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bc657611bc6611b8d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bf557611bf5611b8d565b604052919050565b600082601f830112611c0e57600080fd5b813567ffffffffffffffff811115611c2857611c28611b8d565b611c3b601f8201601f1916602001611bcc565b818152846020838601011115611c5057600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611c8757611c87611b8d565b5060051b60200190565b60008060008060008060c08789031215611caa57600080fd5b8635955060208088013567ffffffffffffffff80821115611cca57600080fd5b611cd68b838c01611bfd565b975060408a0135915080821115611cec57600080fd5b508801601f81018a13611cfe57600080fd5b8035611d11611d0c82611c6d565b611bcc565b81815260059190911b8201830190838101908c831115611d3057600080fd5b928401925b82841015611d4e57833582529284019290840190611d35565b8098505050505050611d6260608801611a76565b9250611d7060808801611a76565b915060a087013590509295509295509295565b8035600281900b8114611a8157600080fd5b60008060008060808587031215611dab57600080fd5b843593506020850135611dbd81611a5e565b9250611dcb60408601611d83565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b60048110611e0f57634e487b7160e01b600052602160045260246000fd5b9052565b8315158152821515602082015260608101611e316040830184611df1565b949350505050565b600060208284031215611e4b57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015611b1b5781516001600160a01b031687529582019590820190600101611e66565b608081526000611e9e6080830187611e52565b82810360208481019190915286518083528782019282019060005b81811015611ed857845160020b83529383019391830191600101611eb9565b50508481036040860152611eec8188611aeb565b858103606087015286518082528388019450908301915060005b81811015611f24578451151583529383019391830191600101611f06565b50909998505050505050505050565b806080810183101561136b57600080fd5b60008060008060006101c08688031215611f5d57600080fd5b85359450611f6e8760208801611f33565b9350611f7d8760a08801611f33565b9250610120860135611f8e81611b39565b9150611f9e876101408801611f33565b90509295509295909350565b6000806000806000806101c08789031215611fc457600080fd5b60a0870188811115611fd557600080fd5b879650611fe28982611f33565b95505061012087013567ffffffffffffffff8082111561200157600080fd5b61200d8a838b01611bfd565b955061014089013591508082111561202457600080fd5b5061203189828a01611bfd565b9350508761017f88011261204457600080fd5b61204c611ba3565b806101a089018a81111561205f57600080fd5b6101608a015b8181101561208657803561207881611a5e565b845260209384019301612065565b50819450803593505050509295509295509295565b83151581526060602082015260006120b66060830185611aeb565b9050826040830152949350505050565b6000806000606084860312156120db57600080fd5b6120e484611d83565b92506120f260208501611d83565b915061210060408501611d83565b90509250925092565b8060005b60028110156103a35781516001600160a01b031684526020938401939091019060010161210d565b8060005b60028110156103a3578151845260209384019390910190600101612139565b6001600160a01b03861681526020810185905260e0810161217c6040830186612109565b6121896080830185612135565b8260c08301529695505050505050565b600082601f8301126121aa57600080fd5b815160206121ba611d0c83611c6d565b82815260059290921b840181019181810190868411156121d957600080fd5b8286015b848110156121f457805183529183019183016121dd565b509695505050505050565b60006020828403121561221157600080fd5b815167ffffffffffffffff81111561222857600080fd5b611e3184828501612199565b8281526040810161178a6020830184611df1565b6000610100612257838a612109565b80604084015261226981840189611e52565b9050828103606084015261227d8188611aeb565b905082810360808401526122918187611aeb565b9150508360a08301526122a760c0830184612135565b979650505050505050565b600080604083850312156122c557600080fd5b82516122d081611a5e565b6020939093015192949293505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761136b5761136b6122e0565b634e487b7160e01b600052601260045260246000fd5b6000826123325761233261230d565b500490565b8181038181111561136b5761136b6122e0565b60006020828403121561235c57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561136b5761136b6122e0565b60006001820161239e5761239e6122e0565b5060010190565b6000602082840312156123b757600080fd5b813561178a81611a5e565b6000602082840312156123d457600080fd5b61178a82611d83565b6000815180845260005b81811015612403576020818501810151868301820152016123e7565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061178a60208301846123dd565b82815260a0810160808360208401379392505050565b600061018061245b838e612109565b80604084015261246d8184018d611e52565b90508281036060840152612481818c611aeb565b6001600160a01b038b8116608086015260a085018b9052891660c085015283810360e085015290506124b381886123dd565b915050841515610100830152836101208301526124d4610140830184612135565b9b9a5050505050505050505050565b6000602082840312156124f557600080fd5b815161178a81611b39565b6000806040838503121561251357600080fd5b505080516020909101519092909150565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c081016103126080830184612135565b6000806040838503121561256b57600080fd5b82519150602083015167ffffffffffffffff81111561258957600080fd5b61259585828601612199565b9150509250929050565b60008160020b8360020b806125b6576125b661230d565b627fffff198214600019821416156125d0576125d06122e0565b90059392505050565b60008260020b8260020b028060020b91508082146125f9576125f96122e0565b5092915050565b600282810b9082900b03627fffff198112627fffff8213171561136b5761136b6122e0565b600281810b9083900b01627fffff8113627fffff198212171561136b5761136b6122e0565b60006020828403121561265c57600080fd5b815161178a81611a5e565b60008060006060848603121561267c57600080fd5b835192506020840151915060408401519050925092509256fea2646970667358221220960a7cfdd680a7ab04a4cd0ca5d2dcdfe140699c45ad617b3e7eeb5716ec162064736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c80636e81b629116100655780636e81b62914610150578063b8b4a44914610173578063bd13c52914610193578063cd8e20e7146101c257600080fd5b80631c2040d5146100975780634aa00915146100cd57806350d2e0ba146100ef57806351265e891461012e575b600080fd5b8180156100a357600080fd5b506100b76100b2366004611a86565b6101ef565b6040516100c49190611b26565b60405180910390f35b8180156100d957600080fd5b506100ed6100e8366004611b47565b61031c565b005b8180156100fb57600080fd5b5061010f61010a366004611c91565b6103a9565b604080516001600160a01b0390931683526020830191909152016100c4565b61014161013c366004611d95565b610504565b6040516100c493929190611e13565b61016361015e366004611e39565b6106ba565b6040516100c49493929190611e8b565b81801561017f57600080fd5b506100ed61018e366004611f44565b610a7d565b81801561019f57600080fd5b506101b36101ae366004611faa565b610dc8565b6040516100c49392919061209b565b6101d56101d03660046120c6565b611293565b60408051600293840b81529190920b6020820152016100c4565b606073__$295fb458e6648e6381ea46363bb426e5e7$__634b4bd6f7888860405180604001604052808a6001600160a01b03166001600160a01b03168152602001896001600160a01b03166001600160a01b0316815250604051806040016040528061027e8960008e6001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b81526001600160a01b038b16600090815260208a81526040909120549101906102a690611358565b815250886040518663ffffffff1660e01b81526004016102ca959493929190612158565b600060405180830381865af41580156102e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261030f91908101906121ff565b90505b9695505050505050565b60008215610395576040516335ffd9a360e11b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__90636bffb346906103609060058801908690600401612234565b60006040518083038186803b15801561037857600080fd5b505af415801561038c573d6000803e3d6000fd5b50505050600190505b80156103a3576000600e8501555b50505050565b6000806103b46119c4565b6040805180820190915260028a01546001600160a01b03908116825260038b01541660208201526103e9908290868b8a611371565b73__$79fe6ec7a3db45dafbed12dca1c6dad764$__6314ad109e6040518060400160405280886001600160a01b03166001600160a01b031681526020016104338560200151611557565b6001600160a01b0316905283516040808601516060870151825180840184526080890151815260a0890151602082015292516001600160e01b031960e088901b1681526104879594938f9291600401612248565b6040805180830381865af41580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c791906122b2565b909350915081156104f857620186a06104e16064846122f6565b6104eb9190612323565b6104f59083612337565b91505b50965096945050505050565b60008060008660030160149054906101000a900460ff16156106a35760028701546003880154604051637fd6c0a160e01b81526001600160a01b03808a16600483015292831660248201529116604482015260009073__$8f1afe7577f9ab973017c74eca19b86f3c$__90637fd6c0a190606401602060405180830381865af4158015610595573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b9919061234a565b604080516060810190915260058a01805492935061067492829060ff1660038111156105e7576105e7611ddb565b60038111156105f8576105f8611ddb565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161061857505050918352505060408051608081019182905260209092019190600584019060049082845b8154815260200190600101908083116106515750505050508152505082876115bb565b9093509150828061069b575061068982611733565b15801561069b575061069b8887611750565b9350506106b0565b6106ad8786611750565b92505b9450945094915050565b60408051600480825260a082019092526060918291829182919060208201608080368337505060408051600480825260a08201909252929650905060208201608080368337505060408051600d8082526101c082019092529295509050602082016101a0803683375050604080516002808252606082018352939550929150602083019080368337505050600286015485519192506001600160a01b031690859060009061076a5761076a612363565b6001600160a01b039283166020918202929092010152600386015485519116908590600190811061079d5761079d612363565b6001600160a01b03928316602091820292909201015285548551911690859060029081106107cd576107cd612363565b6001600160a01b039283166020918202929092010152600186015485519116908590600390811061080057610800612363565b60200260200101906001600160a01b031690816001600160a01b0316815250508460030160169054906101000a900460020b8360008151811061084557610845612363565b600292830b602091820292909201015260038601548451600160c81b90910490910b908490600190811061087b5761087b612363565b600292830b602091820292909201015260038601548451600160e01b909104820b91859181106108ad576108ad612363565b600292830b602091820292909201015260048601548451910b90849060039081106108da576108da612363565b602002602001019060020b908160020b815250508460040160039054906101000a90046001600160801b03166001600160801b03168260008151811061092257610922612363565b6020908102919091010152600585015460ff16600381111561094657610946611ddb565b8260018151811061095957610959612363565b60200260200101818152505084600e01548260038151811061097d5761097d612363565b60200260200101818152505060005b60048110156109e3576006860181600481106109aa576109aa612363565b0154836109b8836004612379565b815181106109c8576109c8612363565b60209081029190910101526109dc8161238c565b905061098c565b5084600f015482600c815181106109fc576109fc612363565b6020026020010181815250508460030160149054906101000a900460ff1681600081518110610a2d57610a2d612363565b6020026020010190151590811515815250508460030160159054906101000a900460ff1681600181518110610a6457610a64612363565b6020026020010190151590811515815250509193509193565b610a8a60208501856123a5565b85546001600160a01b0319166001600160a01b03919091161785556000610ab760408601602087016123a5565b90506000610acb60608701604088016123a5565b90506000610adf60808801606089016123a5565b9050610aee60208701876123c2565b60038901805462ffffff92909216600160b01b0262ffffff60b01b19909216919091179055610b2360408701602088016123c2565b60038901805462ffffff92909216600160c81b0262ffffff60c81b19909216919091179055610b5860608701604088016123c2565b60038901805462ffffff92909216600160e01b0262ffffff60e01b19909216919091179055610b8d60808701606088016123c2565b60048901805462ffffff191662ffffff929092169190911790556001600160a01b038281169084161480610bd25750806001600160a01b0316836001600160a01b0316145b60405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525090610c275760405162461bcd60e51b8152600401610c1e9190612423565b60405180910390fd5b50816001600160a01b0316836001600160a01b031603610c84576002880180546001600160a01b038085166001600160a01b031990921691909117909155600389018054600161ff0160a01b031916918316919091179055610cc9565b6002880180546001600160a01b038084166001600160a01b031990921691909117909155600389018054600161ff0160a01b03191691841691909117600160a81b1790555b8415610dbe5760038801805460ff60a01b1916600160a01b1790556040516335ffd9a360e11b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__90636bffb34690610d219060058c0190600190600401612234565b60006040518083038186803b158015610d3957600080fd5b505af4158015610d4d573d6000803e3d6000fd5b5050604051630593c4c960e01b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250630593c4c99150610d8d9060058c01908890600401612436565b60006040518083038186803b158015610da557600080fd5b505af4158015610db9573d6000803e3d6000fd5b505050505b5050505050505050565b600060606000610dd6611a03565b610de360208b018b6123a5565b6001600160a01b03166020820152896001602002016020810190610e0791906123a5565b6001600160a01b03166040820152896002602002016020810190610e2b91906123a5565b6001600160a01b03166060820152896003602002016020810190610e4f91906123a5565b6001600160a01b03166080820152896004602002016020810190610e7391906123a5565b6001600160a01b031660a0820152883560c0820152602089013560e0820152604089013561010082015280516060820151610eb49190889088908b90611371565b73__$79fe6ec7a3db45dafbed12dca1c6dad764$__637545be26604051806040016040528084608001516001600160a01b03166001600160a01b03168152602001610f06856000015160200151611557565b6001600160a01b03166001600160a01b031681525083600001516000015184600001516040015185602001518660c0015187604001518f60006001600160a01b03168a604001516001600160a01b0316148a600001516060015160405180604001604052808d600001516080015181526020018d6000015160a001518152506040518b63ffffffff1660e01b8152600401610faa9a9998979695949392919061244c565b602060405180830381865af4158015610fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610feb91906124e3565b93508060e0015160001461115857805151805173__$8f1afe7577f9ab973017c74eca19b86f3c$__9163890ffb849160009061102957611029612363565b60200260200101518360e001518460a0015185610100015186600001516000015160008151811061105c5761105c612363565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061234a565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af4158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190612500565b50505b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63ac2a37d6826080015183610100015184600001516000015160008151811061119857611198612363565b60200260200101518560000151600001516001815181106111bb576111bb612363565b602002602001015160405180604001604052808860000151604001516000815181106111e9576111e9612363565b6020026020010151815260200188600001516040015160018151811061121157611211612363565b60200260200101518152506040518663ffffffff1660e01b815260040161123c959493929190612524565b600060405180830381865af4158015611259573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112819190810190612558565b949b949a509850929650505050505050565b60008060008560020b1280156112c45750600285900b836112b4818861259f565b6112be91906125d9565b60020b14155b156112fc57826001816112d78789612600565b6112e1919061259f565b6112eb9190612600565b6112f591906125d9565b915061131f565b82806113088688612600565b611312919061259f565b61131c91906125d9565b91505b8360020b600014611344576113358460026125d9565b61133f9083612625565b61134e565b61134e8383612625565b9050935093915050565b60008115611366578161136b565b620186a05b92915050565b6001600160a01b0381166020860181905260405163124fdbb760e21b8152600481019190915273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063493f6edc9060240160006040518083038186803b1580156113ce57600080fd5b505af41580156113e2573d6000803e3d6000fd5b505050506113ef82611791565b6060860181905261140090836117b8565b60a0870152608086015260408051600280825260608201835290916020830190803683375050508086528451602086015182519192909160009061144657611446612363565b60200260200101876000015160018151811061146457611464612363565b6001600160a01b0393841660209182029290920101529116905260408051600280825260608201909252908160200160208202803683375050506040860152845180516114ed9185916000919082906114bf576114bf612363565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b856040015160008151811061150457611504612363565b60200260200101818152505061152d83600087600001516001815181106114bf576114bf612363565b856040015160018151811061154457611544612363565b6020026020010181815250505050505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b919061264a565b60008080855160038111156115d2576115d2611ddb565b14611718576001855160038111156115ec576115ec611ddb565b0361164c576020850151518411158061160a57506020850151518311155b1561161b5750600190506002611718565b6020850151604001518410158061163a57506020850151604001518310155b1561164757506001905060035b611718565b60028551600381111561166157611661611ddb565b036116c15760208581015101518410801590611684575060208581015101518310155b156116475760208501516040015160019250841015806116ac57506020850151604001518310155b156116b957506003611718565b506001611718565b60208501516060015184118015906116e157506020850151606001518311155b156117185760208581015101516001925084111580611707575060208581015101518311155b1561171457506002611718565b5060015b8182611725578551611727565b815b91509150935093915050565b6000600182600381111561174957611749611ddb565b1192915050565b6003820154600483015460009161178a918491600160c81b8104600290810b92600160e01b8304820b92600160b01b9004820b910b61191a565b9392505050565b600081516000036117a457506000919050565b8180602001905181019061136b919061234a565b6000808315806117c85750600284145b1561184c57828060200190518101906117e19190612500565b925050670de0b6b3a7640000821115806117fc575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118465760405162461bcd60e51b8152600401610c1e9190612423565b50611913565b60408051808201909152601081526f54532d392077726f6e672076616c756560801b6020820152600185146118945760405162461bcd60e51b8152600401610c1e9190612423565b50828060200190518101906118a99190612667565b909350915050670de0b6b3a7640000821115806118c7575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906119115760405162461bcd60e51b8152600401610c1e9190612423565b505b9250929050565b6000600283900b61192b8686612600565b60020b03611954578460020b8660020b128061194d57508360020b8660020b12155b90506119bb565b600060026119628787612600565b61196c919061259f565b9050600061197a8288612625565b90508060020b8860020b136119a157600284900b6119988983612600565b60020b136119b6565b600284900b6119b0828a612600565b60020b12155b925050505b95945050505050565b6040518060c001604052806060815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b604051806101400160405280611a176119c4565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101209091015290565b6001600160a01b0381168114611a7357600080fd5b50565b8035611a8181611a5e565b919050565b60008060008060008060c08789031215611a9f57600080fd5b8635611aaa81611a5e565b9550602087013594506040870135611ac181611a5e565b93506060870135611ad181611a5e565b9598949750929560808101359460a0909101359350915050565b600081518084526020808501945080840160005b83811015611b1b57815187529582019590820190600101611aff565b509495945050505050565b60208152600061178a6020830184611aeb565b8015158114611a7357600080fd5b600080600060608486031215611b5c57600080fd5b833592506020840135611b6e81611b39565b9150604084013560048110611b8257600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bc657611bc6611b8d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bf557611bf5611b8d565b604052919050565b600082601f830112611c0e57600080fd5b813567ffffffffffffffff811115611c2857611c28611b8d565b611c3b601f8201601f1916602001611bcc565b818152846020838601011115611c5057600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611c8757611c87611b8d565b5060051b60200190565b60008060008060008060c08789031215611caa57600080fd5b8635955060208088013567ffffffffffffffff80821115611cca57600080fd5b611cd68b838c01611bfd565b975060408a0135915080821115611cec57600080fd5b508801601f81018a13611cfe57600080fd5b8035611d11611d0c82611c6d565b611bcc565b81815260059190911b8201830190838101908c831115611d3057600080fd5b928401925b82841015611d4e57833582529284019290840190611d35565b8098505050505050611d6260608801611a76565b9250611d7060808801611a76565b915060a087013590509295509295509295565b8035600281900b8114611a8157600080fd5b60008060008060808587031215611dab57600080fd5b843593506020850135611dbd81611a5e565b9250611dcb60408601611d83565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b60048110611e0f57634e487b7160e01b600052602160045260246000fd5b9052565b8315158152821515602082015260608101611e316040830184611df1565b949350505050565b600060208284031215611e4b57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015611b1b5781516001600160a01b031687529582019590820190600101611e66565b608081526000611e9e6080830187611e52565b82810360208481019190915286518083528782019282019060005b81811015611ed857845160020b83529383019391830191600101611eb9565b50508481036040860152611eec8188611aeb565b858103606087015286518082528388019450908301915060005b81811015611f24578451151583529383019391830191600101611f06565b50909998505050505050505050565b806080810183101561136b57600080fd5b60008060008060006101c08688031215611f5d57600080fd5b85359450611f6e8760208801611f33565b9350611f7d8760a08801611f33565b9250610120860135611f8e81611b39565b9150611f9e876101408801611f33565b90509295509295909350565b6000806000806000806101c08789031215611fc457600080fd5b60a0870188811115611fd557600080fd5b879650611fe28982611f33565b95505061012087013567ffffffffffffffff8082111561200157600080fd5b61200d8a838b01611bfd565b955061014089013591508082111561202457600080fd5b5061203189828a01611bfd565b9350508761017f88011261204457600080fd5b61204c611ba3565b806101a089018a81111561205f57600080fd5b6101608a015b8181101561208657803561207881611a5e565b845260209384019301612065565b50819450803593505050509295509295509295565b83151581526060602082015260006120b66060830185611aeb565b9050826040830152949350505050565b6000806000606084860312156120db57600080fd5b6120e484611d83565b92506120f260208501611d83565b915061210060408501611d83565b90509250925092565b8060005b60028110156103a35781516001600160a01b031684526020938401939091019060010161210d565b8060005b60028110156103a3578151845260209384019390910190600101612139565b6001600160a01b03861681526020810185905260e0810161217c6040830186612109565b6121896080830185612135565b8260c08301529695505050505050565b600082601f8301126121aa57600080fd5b815160206121ba611d0c83611c6d565b82815260059290921b840181019181810190868411156121d957600080fd5b8286015b848110156121f457805183529183019183016121dd565b509695505050505050565b60006020828403121561221157600080fd5b815167ffffffffffffffff81111561222857600080fd5b611e3184828501612199565b8281526040810161178a6020830184611df1565b6000610100612257838a612109565b80604084015261226981840189611e52565b9050828103606084015261227d8188611aeb565b905082810360808401526122918187611aeb565b9150508360a08301526122a760c0830184612135565b979650505050505050565b600080604083850312156122c557600080fd5b82516122d081611a5e565b6020939093015192949293505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761136b5761136b6122e0565b634e487b7160e01b600052601260045260246000fd5b6000826123325761233261230d565b500490565b8181038181111561136b5761136b6122e0565b60006020828403121561235c57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561136b5761136b6122e0565b60006001820161239e5761239e6122e0565b5060010190565b6000602082840312156123b757600080fd5b813561178a81611a5e565b6000602082840312156123d457600080fd5b61178a82611d83565b6000815180845260005b81811015612403576020818501810151868301820152016123e7565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061178a60208301846123dd565b82815260a0810160808360208401379392505050565b600061018061245b838e612109565b80604084015261246d8184018d611e52565b90508281036060840152612481818c611aeb565b6001600160a01b038b8116608086015260a085018b9052891660c085015283810360e085015290506124b381886123dd565b915050841515610100830152836101208301526124d4610140830184612135565b9b9a5050505050505050505050565b6000602082840312156124f557600080fd5b815161178a81611b39565b6000806040838503121561251357600080fd5b505080516020909101519092909150565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c081016103126080830184612135565b6000806040838503121561256b57600080fd5b82519150602083015167ffffffffffffffff81111561258957600080fd5b61259585828601612199565b9150509250929050565b60008160020b8360020b806125b6576125b661230d565b627fffff198214600019821416156125d0576125d06122e0565b90059392505050565b60008260020b8260020b028060020b91508082146125f9576125f96122e0565b5092915050565b600282810b9082900b03627fffff198112627fffff8213171561136b5761136b6122e0565b600281810b9083900b01627fffff8113627fffff198212171561136b5761136b6122e0565b60006020828403121561265c57600080fd5b815161178a81611a5e565b60008060006060848603121561267c57600080fd5b835192506020840151915060408401519050925092509256fea2646970667358221220960a7cfdd680a7ab04a4cd0ca5d2dcdfe140699c45ad617b3e7eeb5716ec162064736f6c63430008110033", + "numDeployments": 14, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickRange\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"calcTickRange\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"_beforeDeposit(ITetuConverter,uint256,address,address,uint256,mapping(address => uint256) storage)\":{\"params\":{\"amount_\":\"Amount of tokenA\",\"liquidationThresholds\":\"Dust-thresholds for the tokens A and B\",\"prop0\":\"Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\",\"tokenA\":\"Underlying\",\"tokenB\":\"Not-underlying\"},\"returns\":{\"tokenAmounts\":\"Amounts of token A and B to be deposited, [A, B]\"}},\"getDefaultState(PairBasedStrategyLogicLib.PairState storage)\":{\"returns\":{\"addr\":\"[tokenA, tokenB, pool, profitHolder]\",\"boolValues\":\"[isStablePool, depositorSwapTokens]\",\"nums\":\"[totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter,int24,uint256)\":{\"returns\":{\"needRebalance\":\"A boolean indicating if {rebalanceNoSwaps} should be called\"}},\"quoteWithdrawByAgg(PairBasedStrategyLogicLib.PairState storage,bytes,uint256[],address,ITetuConverter,mapping(address => uint256) storage)\":{\"params\":{\"amounts_\":\"Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\"}},\"setInitialDepositorValues(PairBasedStrategyLogicLib.PairState storage,address[4],int24[4],bool,uint256[4])\":{\"params\":{\"addr\":\"[pool, asset, pool.token0(), pool.token1()] asset: Underlying asset of the depositor.\",\"fuseThresholds\":\"Fuse thresholds for tokens (stable pool only)\",\"pairState\":\"Depositor storage state struct to be initialized\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"withdrawByAggStep(address[5],uint256[4],bytes,bytes,address[2],mapping(address => uint256) storage)\":{\"params\":{\"addr_\":\"[tokenToSwap, aggregator, controller, converter, splitter]\",\"tokens\":\"[underlying, not-underlying] (values been read from pairBase)\",\"values_\":\"[amountToSwap_, profitToCover, oldTotalAssets, not used here]\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to proper proportions\",\"tokenAmounts\":\"Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"_beforeDeposit(ITetuConverter,uint256,address,address,uint256,mapping(address => uint256) storage)\":{\"notice\":\"Prepare array of amounts ready to deposit, borrow missed amounts\"},\"getDefaultState(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Returns the current state of the contract\"},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter,int24,uint256)\":{\"notice\":\"Determine if the strategy needs to be rebalanced.\"},\"quoteWithdrawByAgg(PairBasedStrategyLogicLib.PairState storage,bytes,uint256[],address,ITetuConverter,mapping(address => uint256) storage)\":{\"notice\":\"Get info about a swap required by next call of {withdrawByAggStep} within the given plan\"},\"setInitialDepositorValues(PairBasedStrategyLogicLib.PairState storage,address[4],int24[4],bool,uint256[4])\":{\"notice\":\"Set the initial values to PairState instance\"},\"withdrawByAggStep(address[5],uint256[4],bytes,bytes,address[2],mapping(address => uint256) storage)\":{\"notice\":\"Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\"}},\"notice\":\"Library for the UniV3-like strategies with two tokens in the pool\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":\"PairBasedStrategyLogicLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x6126cb61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c80636e81b629116100655780636e81b62914610150578063b8b4a44914610173578063bd13c52914610193578063cd8e20e7146101c257600080fd5b80631c2040d5146100975780634aa00915146100cd57806350d2e0ba146100ef57806351265e891461012e575b600080fd5b8180156100a357600080fd5b506100b76100b2366004611a86565b6101ef565b6040516100c49190611b26565b60405180910390f35b8180156100d957600080fd5b506100ed6100e8366004611b47565b61031c565b005b8180156100fb57600080fd5b5061010f61010a366004611c91565b6103a9565b604080516001600160a01b0390931683526020830191909152016100c4565b61014161013c366004611d95565b610504565b6040516100c493929190611e13565b61016361015e366004611e39565b6106ba565b6040516100c49493929190611e8b565b81801561017f57600080fd5b506100ed61018e366004611f44565b610a7d565b81801561019f57600080fd5b506101b36101ae366004611faa565b610dc8565b6040516100c49392919061209b565b6101d56101d03660046120c6565b611293565b60408051600293840b81529190920b6020820152016100c4565b60607346aa135654F8A46cDF029059c531EfBd27368220634b4bd6f7888860405180604001604052808a6001600160a01b03166001600160a01b03168152602001896001600160a01b03166001600160a01b0316815250604051806040016040528061027e8960008e6001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b81526001600160a01b038b16600090815260208a81526040909120549101906102a690611358565b815250886040518663ffffffff1660e01b81526004016102ca959493929190612158565b600060405180830381865af41580156102e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261030f91908101906121ff565b90505b9695505050505050565b60008215610395576040516335ffd9a360e11b815273E0D8b85C7Feb11b26e5A2466931088eC5DE7A70390636bffb346906103609060058801908690600401612234565b60006040518083038186803b15801561037857600080fd5b505af415801561038c573d6000803e3d6000fd5b50505050600190505b80156103a3576000600e8501555b50505050565b6000806103b46119c4565b6040805180820190915260028a01546001600160a01b03908116825260038b01541660208201526103e9908290868b8a611371565b73E0D8b85C7Feb11b26e5A2466931088eC5DE7A7036314ad109e6040518060400160405280886001600160a01b03166001600160a01b031681526020016104338560200151611557565b6001600160a01b0316905283516040808601516060870151825180840184526080890151815260a0890151602082015292516001600160e01b031960e088901b1681526104879594938f9291600401612248565b6040805180830381865af41580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c791906122b2565b909350915081156104f857620186a06104e16064846122f6565b6104eb9190612323565b6104f59083612337565b91505b50965096945050505050565b60008060008660030160149054906101000a900460ff16156106a35760028701546003880154604051637fd6c0a160e01b81526001600160a01b03808a16600483015292831660248201529116604482015260009073C92346a144fa75b45b0eDAe966FEAA0E30C82c5590637fd6c0a190606401602060405180830381865af4158015610595573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b9919061234a565b604080516060810190915260058a01805492935061067492829060ff1660038111156105e7576105e7611ddb565b60038111156105f8576105f8611ddb565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161061857505050918352505060408051608081019182905260209092019190600584019060049082845b8154815260200190600101908083116106515750505050508152505082876115bb565b9093509150828061069b575061068982611733565b15801561069b575061069b8887611750565b9350506106b0565b6106ad8786611750565b92505b9450945094915050565b60408051600480825260a082019092526060918291829182919060208201608080368337505060408051600480825260a08201909252929650905060208201608080368337505060408051600d8082526101c082019092529295509050602082016101a0803683375050604080516002808252606082018352939550929150602083019080368337505050600286015485519192506001600160a01b031690859060009061076a5761076a612363565b6001600160a01b039283166020918202929092010152600386015485519116908590600190811061079d5761079d612363565b6001600160a01b03928316602091820292909201015285548551911690859060029081106107cd576107cd612363565b6001600160a01b039283166020918202929092010152600186015485519116908590600390811061080057610800612363565b60200260200101906001600160a01b031690816001600160a01b0316815250508460030160169054906101000a900460020b8360008151811061084557610845612363565b600292830b602091820292909201015260038601548451600160c81b90910490910b908490600190811061087b5761087b612363565b600292830b602091820292909201015260038601548451600160e01b909104820b91859181106108ad576108ad612363565b600292830b602091820292909201015260048601548451910b90849060039081106108da576108da612363565b602002602001019060020b908160020b815250508460040160039054906101000a90046001600160801b03166001600160801b03168260008151811061092257610922612363565b6020908102919091010152600585015460ff16600381111561094657610946611ddb565b8260018151811061095957610959612363565b60200260200101818152505084600e01548260038151811061097d5761097d612363565b60200260200101818152505060005b60048110156109e3576006860181600481106109aa576109aa612363565b0154836109b8836004612379565b815181106109c8576109c8612363565b60209081029190910101526109dc8161238c565b905061098c565b5084600f015482600c815181106109fc576109fc612363565b6020026020010181815250508460030160149054906101000a900460ff1681600081518110610a2d57610a2d612363565b6020026020010190151590811515815250508460030160159054906101000a900460ff1681600181518110610a6457610a64612363565b6020026020010190151590811515815250509193509193565b610a8a60208501856123a5565b85546001600160a01b0319166001600160a01b03919091161785556000610ab760408601602087016123a5565b90506000610acb60608701604088016123a5565b90506000610adf60808801606089016123a5565b9050610aee60208701876123c2565b60038901805462ffffff92909216600160b01b0262ffffff60b01b19909216919091179055610b2360408701602088016123c2565b60038901805462ffffff92909216600160c81b0262ffffff60c81b19909216919091179055610b5860608701604088016123c2565b60038901805462ffffff92909216600160e01b0262ffffff60e01b19909216919091179055610b8d60808701606088016123c2565b60048901805462ffffff191662ffffff929092169190911790556001600160a01b038281169084161480610bd25750806001600160a01b0316836001600160a01b0316145b60405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525090610c275760405162461bcd60e51b8152600401610c1e9190612423565b60405180910390fd5b50816001600160a01b0316836001600160a01b031603610c84576002880180546001600160a01b038085166001600160a01b031990921691909117909155600389018054600161ff0160a01b031916918316919091179055610cc9565b6002880180546001600160a01b038084166001600160a01b031990921691909117909155600389018054600161ff0160a01b03191691841691909117600160a81b1790555b8415610dbe5760038801805460ff60a01b1916600160a01b1790556040516335ffd9a360e11b815273E0D8b85C7Feb11b26e5A2466931088eC5DE7A70390636bffb34690610d219060058c0190600190600401612234565b60006040518083038186803b158015610d3957600080fd5b505af4158015610d4d573d6000803e3d6000fd5b5050604051630593c4c960e01b815273E0D8b85C7Feb11b26e5A2466931088eC5DE7A7039250630593c4c99150610d8d9060058c01908890600401612436565b60006040518083038186803b158015610da557600080fd5b505af4158015610db9573d6000803e3d6000fd5b505050505b5050505050505050565b600060606000610dd6611a03565b610de360208b018b6123a5565b6001600160a01b03166020820152896001602002016020810190610e0791906123a5565b6001600160a01b03166040820152896002602002016020810190610e2b91906123a5565b6001600160a01b03166060820152896003602002016020810190610e4f91906123a5565b6001600160a01b03166080820152896004602002016020810190610e7391906123a5565b6001600160a01b031660a0820152883560c0820152602089013560e0820152604089013561010082015280516060820151610eb49190889088908b90611371565b73E0D8b85C7Feb11b26e5A2466931088eC5DE7A703637545be26604051806040016040528084608001516001600160a01b03166001600160a01b03168152602001610f06856000015160200151611557565b6001600160a01b03166001600160a01b031681525083600001516000015184600001516040015185602001518660c0015187604001518f60006001600160a01b03168a604001516001600160a01b0316148a600001516060015160405180604001604052808d600001516080015181526020018d6000015160a001518152506040518b63ffffffff1660e01b8152600401610faa9a9998979695949392919061244c565b602060405180830381865af4158015610fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610feb91906124e3565b93508060e0015160001461115857805151805173C92346a144fa75b45b0eDAe966FEAA0E30C82c559163890ffb849160009061102957611029612363565b60200260200101518360e001518460a0015185610100015186600001516000015160008151811061105c5761105c612363565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061234a565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af4158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190612500565b50505b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563ac2a37d6826080015183610100015184600001516000015160008151811061119857611198612363565b60200260200101518560000151600001516001815181106111bb576111bb612363565b602002602001015160405180604001604052808860000151604001516000815181106111e9576111e9612363565b6020026020010151815260200188600001516040015160018151811061121157611211612363565b60200260200101518152506040518663ffffffff1660e01b815260040161123c959493929190612524565b600060405180830381865af4158015611259573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112819190810190612558565b949b949a509850929650505050505050565b60008060008560020b1280156112c45750600285900b836112b4818861259f565b6112be91906125d9565b60020b14155b156112fc57826001816112d78789612600565b6112e1919061259f565b6112eb9190612600565b6112f591906125d9565b915061131f565b82806113088688612600565b611312919061259f565b61131c91906125d9565b91505b8360020b600014611344576113358460026125d9565b61133f9083612625565b61134e565b61134e8383612625565b9050935093915050565b60008115611366578161136b565b620186a05b92915050565b6001600160a01b0381166020860181905260405163124fdbb760e21b815260048101919091527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063493f6edc9060240160006040518083038186803b1580156113ce57600080fd5b505af41580156113e2573d6000803e3d6000fd5b505050506113ef82611791565b6060860181905261140090836117b8565b60a0870152608086015260408051600280825260608201835290916020830190803683375050508086528451602086015182519192909160009061144657611446612363565b60200260200101876000015160018151811061146457611464612363565b6001600160a01b0393841660209182029290920101529116905260408051600280825260608201909252908160200160208202803683375050506040860152845180516114ed9185916000919082906114bf576114bf612363565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b856040015160008151811061150457611504612363565b60200260200101818152505061152d83600087600001516001815181106114bf576114bf612363565b856040015160018151811061154457611544612363565b6020026020010181815250505050505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b919061264a565b60008080855160038111156115d2576115d2611ddb565b14611718576001855160038111156115ec576115ec611ddb565b0361164c576020850151518411158061160a57506020850151518311155b1561161b5750600190506002611718565b6020850151604001518410158061163a57506020850151604001518310155b1561164757506001905060035b611718565b60028551600381111561166157611661611ddb565b036116c15760208581015101518410801590611684575060208581015101518310155b156116475760208501516040015160019250841015806116ac57506020850151604001518310155b156116b957506003611718565b506001611718565b60208501516060015184118015906116e157506020850151606001518311155b156117185760208581015101516001925084111580611707575060208581015101518311155b1561171457506002611718565b5060015b8182611725578551611727565b815b91509150935093915050565b6000600182600381111561174957611749611ddb565b1192915050565b6003820154600483015460009161178a918491600160c81b8104600290810b92600160e01b8304820b92600160b01b9004820b910b61191a565b9392505050565b600081516000036117a457506000919050565b8180602001905181019061136b919061234a565b6000808315806117c85750600284145b1561184c57828060200190518101906117e19190612500565b925050670de0b6b3a7640000821115806117fc575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118465760405162461bcd60e51b8152600401610c1e9190612423565b50611913565b60408051808201909152601081526f54532d392077726f6e672076616c756560801b6020820152600185146118945760405162461bcd60e51b8152600401610c1e9190612423565b50828060200190518101906118a99190612667565b909350915050670de0b6b3a7640000821115806118c7575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906119115760405162461bcd60e51b8152600401610c1e9190612423565b505b9250929050565b6000600283900b61192b8686612600565b60020b03611954578460020b8660020b128061194d57508360020b8660020b12155b90506119bb565b600060026119628787612600565b61196c919061259f565b9050600061197a8288612625565b90508060020b8860020b136119a157600284900b6119988983612600565b60020b136119b6565b600284900b6119b0828a612600565b60020b12155b925050505b95945050505050565b6040518060c001604052806060815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b604051806101400160405280611a176119c4565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101209091015290565b6001600160a01b0381168114611a7357600080fd5b50565b8035611a8181611a5e565b919050565b60008060008060008060c08789031215611a9f57600080fd5b8635611aaa81611a5e565b9550602087013594506040870135611ac181611a5e565b93506060870135611ad181611a5e565b9598949750929560808101359460a0909101359350915050565b600081518084526020808501945080840160005b83811015611b1b57815187529582019590820190600101611aff565b509495945050505050565b60208152600061178a6020830184611aeb565b8015158114611a7357600080fd5b600080600060608486031215611b5c57600080fd5b833592506020840135611b6e81611b39565b9150604084013560048110611b8257600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bc657611bc6611b8d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bf557611bf5611b8d565b604052919050565b600082601f830112611c0e57600080fd5b813567ffffffffffffffff811115611c2857611c28611b8d565b611c3b601f8201601f1916602001611bcc565b818152846020838601011115611c5057600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611c8757611c87611b8d565b5060051b60200190565b60008060008060008060c08789031215611caa57600080fd5b8635955060208088013567ffffffffffffffff80821115611cca57600080fd5b611cd68b838c01611bfd565b975060408a0135915080821115611cec57600080fd5b508801601f81018a13611cfe57600080fd5b8035611d11611d0c82611c6d565b611bcc565b81815260059190911b8201830190838101908c831115611d3057600080fd5b928401925b82841015611d4e57833582529284019290840190611d35565b8098505050505050611d6260608801611a76565b9250611d7060808801611a76565b915060a087013590509295509295509295565b8035600281900b8114611a8157600080fd5b60008060008060808587031215611dab57600080fd5b843593506020850135611dbd81611a5e565b9250611dcb60408601611d83565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b60048110611e0f57634e487b7160e01b600052602160045260246000fd5b9052565b8315158152821515602082015260608101611e316040830184611df1565b949350505050565b600060208284031215611e4b57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015611b1b5781516001600160a01b031687529582019590820190600101611e66565b608081526000611e9e6080830187611e52565b82810360208481019190915286518083528782019282019060005b81811015611ed857845160020b83529383019391830191600101611eb9565b50508481036040860152611eec8188611aeb565b858103606087015286518082528388019450908301915060005b81811015611f24578451151583529383019391830191600101611f06565b50909998505050505050505050565b806080810183101561136b57600080fd5b60008060008060006101c08688031215611f5d57600080fd5b85359450611f6e8760208801611f33565b9350611f7d8760a08801611f33565b9250610120860135611f8e81611b39565b9150611f9e876101408801611f33565b90509295509295909350565b6000806000806000806101c08789031215611fc457600080fd5b60a0870188811115611fd557600080fd5b879650611fe28982611f33565b95505061012087013567ffffffffffffffff8082111561200157600080fd5b61200d8a838b01611bfd565b955061014089013591508082111561202457600080fd5b5061203189828a01611bfd565b9350508761017f88011261204457600080fd5b61204c611ba3565b806101a089018a81111561205f57600080fd5b6101608a015b8181101561208657803561207881611a5e565b845260209384019301612065565b50819450803593505050509295509295509295565b83151581526060602082015260006120b66060830185611aeb565b9050826040830152949350505050565b6000806000606084860312156120db57600080fd5b6120e484611d83565b92506120f260208501611d83565b915061210060408501611d83565b90509250925092565b8060005b60028110156103a35781516001600160a01b031684526020938401939091019060010161210d565b8060005b60028110156103a3578151845260209384019390910190600101612139565b6001600160a01b03861681526020810185905260e0810161217c6040830186612109565b6121896080830185612135565b8260c08301529695505050505050565b600082601f8301126121aa57600080fd5b815160206121ba611d0c83611c6d565b82815260059290921b840181019181810190868411156121d957600080fd5b8286015b848110156121f457805183529183019183016121dd565b509695505050505050565b60006020828403121561221157600080fd5b815167ffffffffffffffff81111561222857600080fd5b611e3184828501612199565b8281526040810161178a6020830184611df1565b6000610100612257838a612109565b80604084015261226981840189611e52565b9050828103606084015261227d8188611aeb565b905082810360808401526122918187611aeb565b9150508360a08301526122a760c0830184612135565b979650505050505050565b600080604083850312156122c557600080fd5b82516122d081611a5e565b6020939093015192949293505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761136b5761136b6122e0565b634e487b7160e01b600052601260045260246000fd5b6000826123325761233261230d565b500490565b8181038181111561136b5761136b6122e0565b60006020828403121561235c57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561136b5761136b6122e0565b60006001820161239e5761239e6122e0565b5060010190565b6000602082840312156123b757600080fd5b813561178a81611a5e565b6000602082840312156123d457600080fd5b61178a82611d83565b6000815180845260005b81811015612403576020818501810151868301820152016123e7565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061178a60208301846123dd565b82815260a0810160808360208401379392505050565b600061018061245b838e612109565b80604084015261246d8184018d611e52565b90508281036060840152612481818c611aeb565b6001600160a01b038b8116608086015260a085018b9052891660c085015283810360e085015290506124b381886123dd565b915050841515610100830152836101208301526124d4610140830184612135565b9b9a5050505050505050505050565b6000602082840312156124f557600080fd5b815161178a81611b39565b6000806040838503121561251357600080fd5b505080516020909101519092909150565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c081016103126080830184612135565b6000806040838503121561256b57600080fd5b82519150602083015167ffffffffffffffff81111561258957600080fd5b61259585828601612199565b9150509250929050565b60008160020b8360020b806125b6576125b661230d565b627fffff198214600019821416156125d0576125d06122e0565b90059392505050565b60008260020b8260020b028060020b91508082146125f9576125f96122e0565b5092915050565b600282810b9082900b03627fffff198112627fffff8213171561136b5761136b6122e0565b600281810b9083900b01627fffff8113627fffff198212171561136b5761136b6122e0565b60006020828403121561265c57600080fd5b815161178a81611a5e565b60008060006060848603121561267c57600080fd5b835192506020840151915060408401519050925092509256fea26469706673582212200c880b349c2a67ceb54732bf3fcbba62528f3dfc262865edb6dea939a390492564736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100925760003560e01c80636e81b629116100655780636e81b62914610150578063b8b4a44914610173578063bd13c52914610193578063cd8e20e7146101c257600080fd5b80631c2040d5146100975780634aa00915146100cd57806350d2e0ba146100ef57806351265e891461012e575b600080fd5b8180156100a357600080fd5b506100b76100b2366004611a86565b6101ef565b6040516100c49190611b26565b60405180910390f35b8180156100d957600080fd5b506100ed6100e8366004611b47565b61031c565b005b8180156100fb57600080fd5b5061010f61010a366004611c91565b6103a9565b604080516001600160a01b0390931683526020830191909152016100c4565b61014161013c366004611d95565b610504565b6040516100c493929190611e13565b61016361015e366004611e39565b6106ba565b6040516100c49493929190611e8b565b81801561017f57600080fd5b506100ed61018e366004611f44565b610a7d565b81801561019f57600080fd5b506101b36101ae366004611faa565b610dc8565b6040516100c49392919061209b565b6101d56101d03660046120c6565b611293565b60408051600293840b81529190920b6020820152016100c4565b606073__$295fb458e6648e6381ea46363bb426e5e7$__634b4bd6f7888860405180604001604052808a6001600160a01b03166001600160a01b03168152602001896001600160a01b03166001600160a01b0316815250604051806040016040528061027e8960008e6001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b81526001600160a01b038b16600090815260208a81526040909120549101906102a690611358565b815250886040518663ffffffff1660e01b81526004016102ca959493929190612158565b600060405180830381865af41580156102e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261030f91908101906121ff565b90505b9695505050505050565b60008215610395576040516335ffd9a360e11b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__90636bffb346906103609060058801908690600401612234565b60006040518083038186803b15801561037857600080fd5b505af415801561038c573d6000803e3d6000fd5b50505050600190505b80156103a3576000600e8501555b50505050565b6000806103b46119c4565b6040805180820190915260028a01546001600160a01b03908116825260038b01541660208201526103e9908290868b8a611371565b73__$79fe6ec7a3db45dafbed12dca1c6dad764$__6314ad109e6040518060400160405280886001600160a01b03166001600160a01b031681526020016104338560200151611557565b6001600160a01b0316905283516040808601516060870151825180840184526080890151815260a0890151602082015292516001600160e01b031960e088901b1681526104879594938f9291600401612248565b6040805180830381865af41580156104a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c791906122b2565b909350915081156104f857620186a06104e16064846122f6565b6104eb9190612323565b6104f59083612337565b91505b50965096945050505050565b60008060008660030160149054906101000a900460ff16156106a35760028701546003880154604051637fd6c0a160e01b81526001600160a01b03808a16600483015292831660248201529116604482015260009073__$8f1afe7577f9ab973017c74eca19b86f3c$__90637fd6c0a190606401602060405180830381865af4158015610595573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b9919061234a565b604080516060810190915260058a01805492935061067492829060ff1660038111156105e7576105e7611ddb565b60038111156105f8576105f8611ddb565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161061857505050918352505060408051608081019182905260209092019190600584019060049082845b8154815260200190600101908083116106515750505050508152505082876115bb565b9093509150828061069b575061068982611733565b15801561069b575061069b8887611750565b9350506106b0565b6106ad8786611750565b92505b9450945094915050565b60408051600480825260a082019092526060918291829182919060208201608080368337505060408051600480825260a08201909252929650905060208201608080368337505060408051600d8082526101c082019092529295509050602082016101a0803683375050604080516002808252606082018352939550929150602083019080368337505050600286015485519192506001600160a01b031690859060009061076a5761076a612363565b6001600160a01b039283166020918202929092010152600386015485519116908590600190811061079d5761079d612363565b6001600160a01b03928316602091820292909201015285548551911690859060029081106107cd576107cd612363565b6001600160a01b039283166020918202929092010152600186015485519116908590600390811061080057610800612363565b60200260200101906001600160a01b031690816001600160a01b0316815250508460030160169054906101000a900460020b8360008151811061084557610845612363565b600292830b602091820292909201015260038601548451600160c81b90910490910b908490600190811061087b5761087b612363565b600292830b602091820292909201015260038601548451600160e01b909104820b91859181106108ad576108ad612363565b600292830b602091820292909201015260048601548451910b90849060039081106108da576108da612363565b602002602001019060020b908160020b815250508460040160039054906101000a90046001600160801b03166001600160801b03168260008151811061092257610922612363565b6020908102919091010152600585015460ff16600381111561094657610946611ddb565b8260018151811061095957610959612363565b60200260200101818152505084600e01548260038151811061097d5761097d612363565b60200260200101818152505060005b60048110156109e3576006860181600481106109aa576109aa612363565b0154836109b8836004612379565b815181106109c8576109c8612363565b60209081029190910101526109dc8161238c565b905061098c565b5084600f015482600c815181106109fc576109fc612363565b6020026020010181815250508460030160149054906101000a900460ff1681600081518110610a2d57610a2d612363565b6020026020010190151590811515815250508460030160159054906101000a900460ff1681600181518110610a6457610a64612363565b6020026020010190151590811515815250509193509193565b610a8a60208501856123a5565b85546001600160a01b0319166001600160a01b03919091161785556000610ab760408601602087016123a5565b90506000610acb60608701604088016123a5565b90506000610adf60808801606089016123a5565b9050610aee60208701876123c2565b60038901805462ffffff92909216600160b01b0262ffffff60b01b19909216919091179055610b2360408701602088016123c2565b60038901805462ffffff92909216600160c81b0262ffffff60c81b19909216919091179055610b5860608701604088016123c2565b60038901805462ffffff92909216600160e01b0262ffffff60e01b19909216919091179055610b8d60808701606088016123c2565b60048901805462ffffff191662ffffff929092169190911790556001600160a01b038281169084161480610bd25750806001600160a01b0316836001600160a01b0316145b60405180604001604052806015815260200174141094cb4d48125b98dbdc9c9958dd08185cdcd95d605a1b81525090610c275760405162461bcd60e51b8152600401610c1e9190612423565b60405180910390fd5b50816001600160a01b0316836001600160a01b031603610c84576002880180546001600160a01b038085166001600160a01b031990921691909117909155600389018054600161ff0160a01b031916918316919091179055610cc9565b6002880180546001600160a01b038084166001600160a01b031990921691909117909155600389018054600161ff0160a01b03191691841691909117600160a81b1790555b8415610dbe5760038801805460ff60a01b1916600160a01b1790556040516335ffd9a360e11b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__90636bffb34690610d219060058c0190600190600401612234565b60006040518083038186803b158015610d3957600080fd5b505af4158015610d4d573d6000803e3d6000fd5b5050604051630593c4c960e01b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250630593c4c99150610d8d9060058c01908890600401612436565b60006040518083038186803b158015610da557600080fd5b505af4158015610db9573d6000803e3d6000fd5b505050505b5050505050505050565b600060606000610dd6611a03565b610de360208b018b6123a5565b6001600160a01b03166020820152896001602002016020810190610e0791906123a5565b6001600160a01b03166040820152896002602002016020810190610e2b91906123a5565b6001600160a01b03166060820152896003602002016020810190610e4f91906123a5565b6001600160a01b03166080820152896004602002016020810190610e7391906123a5565b6001600160a01b031660a0820152883560c0820152602089013560e0820152604089013561010082015280516060820151610eb49190889088908b90611371565b73__$79fe6ec7a3db45dafbed12dca1c6dad764$__637545be26604051806040016040528084608001516001600160a01b03166001600160a01b03168152602001610f06856000015160200151611557565b6001600160a01b03166001600160a01b031681525083600001516000015184600001516040015185602001518660c0015187604001518f60006001600160a01b03168a604001516001600160a01b0316148a600001516060015160405180604001604052808d600001516080015181526020018d6000015160a001518152506040518b63ffffffff1660e01b8152600401610faa9a9998979695949392919061244c565b602060405180830381865af4158015610fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610feb91906124e3565b93508060e0015160001461115857805151805173__$8f1afe7577f9ab973017c74eca19b86f3c$__9163890ffb849160009061102957611029612363565b60200260200101518360e001518460a0015185610100015186600001516000015160008151811061105c5761105c612363565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061234a565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af4158015611131573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111559190612500565b50505b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63ac2a37d6826080015183610100015184600001516000015160008151811061119857611198612363565b60200260200101518560000151600001516001815181106111bb576111bb612363565b602002602001015160405180604001604052808860000151604001516000815181106111e9576111e9612363565b6020026020010151815260200188600001516040015160018151811061121157611211612363565b60200260200101518152506040518663ffffffff1660e01b815260040161123c959493929190612524565b600060405180830381865af4158015611259573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112819190810190612558565b949b949a509850929650505050505050565b60008060008560020b1280156112c45750600285900b836112b4818861259f565b6112be91906125d9565b60020b14155b156112fc57826001816112d78789612600565b6112e1919061259f565b6112eb9190612600565b6112f591906125d9565b915061131f565b82806113088688612600565b611312919061259f565b61131c91906125d9565b91505b8360020b600014611344576113358460026125d9565b61133f9083612625565b61134e565b61134e8383612625565b9050935093915050565b60008115611366578161136b565b620186a05b92915050565b6001600160a01b0381166020860181905260405163124fdbb760e21b8152600481019190915273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063493f6edc9060240160006040518083038186803b1580156113ce57600080fd5b505af41580156113e2573d6000803e3d6000fd5b505050506113ef82611791565b6060860181905261140090836117b8565b60a0870152608086015260408051600280825260608201835290916020830190803683375050508086528451602086015182519192909160009061144657611446612363565b60200260200101876000015160018151811061146457611464612363565b6001600160a01b0393841660209182029290920101529116905260408051600280825260608201909252908160200160208202803683375050506040860152845180516114ed9185916000919082906114bf576114bf612363565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054611358565b856040015160008151811061150457611504612363565b60200260200101818152505061152d83600087600001516001815181106114bf576114bf612363565b856040015160018151811061154457611544612363565b6020026020010181815250505050505050565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611597573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136b919061264a565b60008080855160038111156115d2576115d2611ddb565b14611718576001855160038111156115ec576115ec611ddb565b0361164c576020850151518411158061160a57506020850151518311155b1561161b5750600190506002611718565b6020850151604001518410158061163a57506020850151604001518310155b1561164757506001905060035b611718565b60028551600381111561166157611661611ddb565b036116c15760208581015101518410801590611684575060208581015101518310155b156116475760208501516040015160019250841015806116ac57506020850151604001518310155b156116b957506003611718565b506001611718565b60208501516060015184118015906116e157506020850151606001518311155b156117185760208581015101516001925084111580611707575060208581015101518311155b1561171457506002611718565b5060015b8182611725578551611727565b815b91509150935093915050565b6000600182600381111561174957611749611ddb565b1192915050565b6003820154600483015460009161178a918491600160c81b8104600290810b92600160e01b8304820b92600160b01b9004820b910b61191a565b9392505050565b600081516000036117a457506000919050565b8180602001905181019061136b919061234a565b6000808315806117c85750600284145b1561184c57828060200190518101906117e19190612500565b925050670de0b6b3a7640000821115806117fc575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906118465760405162461bcd60e51b8152600401610c1e9190612423565b50611913565b60408051808201909152601081526f54532d392077726f6e672076616c756560801b6020820152600185146118945760405162461bcd60e51b8152600401610c1e9190612423565b50828060200190518101906118a99190612667565b909350915050670de0b6b3a7640000821115806118c7575060001982145b6040518060400160405280601381526020017254532d333020696e76616c69642076616c756560681b815250906119115760405162461bcd60e51b8152600401610c1e9190612423565b505b9250929050565b6000600283900b61192b8686612600565b60020b03611954578460020b8660020b128061194d57508360020b8660020b12155b90506119bb565b600060026119628787612600565b61196c919061259f565b9050600061197a8288612625565b90508060020b8860020b136119a157600284900b6119988983612600565b60020b136119b6565b600284900b6119b0828a612600565b60020b12155b925050505b95945050505050565b6040518060c001604052806060815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b604051806101400160405280611a176119c4565b815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101209091015290565b6001600160a01b0381168114611a7357600080fd5b50565b8035611a8181611a5e565b919050565b60008060008060008060c08789031215611a9f57600080fd5b8635611aaa81611a5e565b9550602087013594506040870135611ac181611a5e565b93506060870135611ad181611a5e565b9598949750929560808101359460a0909101359350915050565b600081518084526020808501945080840160005b83811015611b1b57815187529582019590820190600101611aff565b509495945050505050565b60208152600061178a6020830184611aeb565b8015158114611a7357600080fd5b600080600060608486031215611b5c57600080fd5b833592506020840135611b6e81611b39565b9150604084013560048110611b8257600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bc657611bc6611b8d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bf557611bf5611b8d565b604052919050565b600082601f830112611c0e57600080fd5b813567ffffffffffffffff811115611c2857611c28611b8d565b611c3b601f8201601f1916602001611bcc565b818152846020838601011115611c5057600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611c8757611c87611b8d565b5060051b60200190565b60008060008060008060c08789031215611caa57600080fd5b8635955060208088013567ffffffffffffffff80821115611cca57600080fd5b611cd68b838c01611bfd565b975060408a0135915080821115611cec57600080fd5b508801601f81018a13611cfe57600080fd5b8035611d11611d0c82611c6d565b611bcc565b81815260059190911b8201830190838101908c831115611d3057600080fd5b928401925b82841015611d4e57833582529284019290840190611d35565b8098505050505050611d6260608801611a76565b9250611d7060808801611a76565b915060a087013590509295509295509295565b8035600281900b8114611a8157600080fd5b60008060008060808587031215611dab57600080fd5b843593506020850135611dbd81611a5e565b9250611dcb60408601611d83565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b60048110611e0f57634e487b7160e01b600052602160045260246000fd5b9052565b8315158152821515602082015260608101611e316040830184611df1565b949350505050565b600060208284031215611e4b57600080fd5b5035919050565b600081518084526020808501945080840160005b83811015611b1b5781516001600160a01b031687529582019590820190600101611e66565b608081526000611e9e6080830187611e52565b82810360208481019190915286518083528782019282019060005b81811015611ed857845160020b83529383019391830191600101611eb9565b50508481036040860152611eec8188611aeb565b858103606087015286518082528388019450908301915060005b81811015611f24578451151583529383019391830191600101611f06565b50909998505050505050505050565b806080810183101561136b57600080fd5b60008060008060006101c08688031215611f5d57600080fd5b85359450611f6e8760208801611f33565b9350611f7d8760a08801611f33565b9250610120860135611f8e81611b39565b9150611f9e876101408801611f33565b90509295509295909350565b6000806000806000806101c08789031215611fc457600080fd5b60a0870188811115611fd557600080fd5b879650611fe28982611f33565b95505061012087013567ffffffffffffffff8082111561200157600080fd5b61200d8a838b01611bfd565b955061014089013591508082111561202457600080fd5b5061203189828a01611bfd565b9350508761017f88011261204457600080fd5b61204c611ba3565b806101a089018a81111561205f57600080fd5b6101608a015b8181101561208657803561207881611a5e565b845260209384019301612065565b50819450803593505050509295509295509295565b83151581526060602082015260006120b66060830185611aeb565b9050826040830152949350505050565b6000806000606084860312156120db57600080fd5b6120e484611d83565b92506120f260208501611d83565b915061210060408501611d83565b90509250925092565b8060005b60028110156103a35781516001600160a01b031684526020938401939091019060010161210d565b8060005b60028110156103a3578151845260209384019390910190600101612139565b6001600160a01b03861681526020810185905260e0810161217c6040830186612109565b6121896080830185612135565b8260c08301529695505050505050565b600082601f8301126121aa57600080fd5b815160206121ba611d0c83611c6d565b82815260059290921b840181019181810190868411156121d957600080fd5b8286015b848110156121f457805183529183019183016121dd565b509695505050505050565b60006020828403121561221157600080fd5b815167ffffffffffffffff81111561222857600080fd5b611e3184828501612199565b8281526040810161178a6020830184611df1565b6000610100612257838a612109565b80604084015261226981840189611e52565b9050828103606084015261227d8188611aeb565b905082810360808401526122918187611aeb565b9150508360a08301526122a760c0830184612135565b979650505050505050565b600080604083850312156122c557600080fd5b82516122d081611a5e565b6020939093015192949293505050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761136b5761136b6122e0565b634e487b7160e01b600052601260045260246000fd5b6000826123325761233261230d565b500490565b8181038181111561136b5761136b6122e0565b60006020828403121561235c57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561136b5761136b6122e0565b60006001820161239e5761239e6122e0565b5060010190565b6000602082840312156123b757600080fd5b813561178a81611a5e565b6000602082840312156123d457600080fd5b61178a82611d83565b6000815180845260005b81811015612403576020818501810151868301820152016123e7565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061178a60208301846123dd565b82815260a0810160808360208401379392505050565b600061018061245b838e612109565b80604084015261246d8184018d611e52565b90508281036060840152612481818c611aeb565b6001600160a01b038b8116608086015260a085018b9052891660c085015283810360e085015290506124b381886123dd565b915050841515610100830152836101208301526124d4610140830184612135565b9b9a5050505050505050505050565b6000602082840312156124f557600080fd5b815161178a81611b39565b6000806040838503121561251357600080fd5b505080516020909101519092909150565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c081016103126080830184612135565b6000806040838503121561256b57600080fd5b82519150602083015167ffffffffffffffff81111561258957600080fd5b61259585828601612199565b9150509250929050565b60008160020b8360020b806125b6576125b661230d565b627fffff198214600019821416156125d0576125d06122e0565b90059392505050565b60008260020b8260020b028060020b91508082146125f9576125f96122e0565b5092915050565b600282810b9082900b03627fffff198112627fffff8213171561136b5761136b6122e0565b600281810b9083900b01627fffff8113627fffff198212171561136b5761136b6122e0565b60006020828403121561265c57600080fd5b815161178a81611a5e565b60008060006060848603121561267c57600080fd5b835192506020840151915060408401519050925092509256fea26469706673582212200c880b349c2a67ceb54732bf3fcbba62528f3dfc262865edb6dea939a390492564736f6c63430008110033", "libraries": { - "BorrowLib": "0xd84c6293b2E190DDd7Ea7F6E00396A840294BDcE", + "BorrowLib": "0x46aa135654F8A46cDF029059c531EfBd27368220", "ConverterStrategyBaseLib2": "0xC92346a144fa75b45b0eDAe966FEAA0E30C82c55", - "PairBasedStrategyLib": "0xE5779B35180c1048562c733A7E62f8Fe1d253C41", + "PairBasedStrategyLib": "0xE0D8b85C7Feb11b26e5A2466931088eC5DE7A703", "StrategyLib2": "0x06c875daA1Dc2E27dd7381EB3b6be4F99553a609" }, "devdoc": { diff --git a/deployments/matic/PairBasedStrategyReader.json b/deployments/matic/PairBasedStrategyReader.json index 1ac5088a..6e210c1b 100644 --- a/deployments/matic/PairBasedStrategyReader.json +++ b/deployments/matic/PairBasedStrategyReader.json @@ -1,5 +1,5 @@ { - "address": "0x64AcD4C418D911Baf2bb467Cb6DA9F75dDDd026E", + "address": "0x68cA4500a40A250E70cD99499B1dC27aB523882E", "abi": [ { "inputs": [], @@ -149,44 +149,44 @@ "type": "function" } ], - "transactionHash": "0x05f3fae480679a3697a88df836e10865ce069de665d479707c9b0da6777024a4", + "transactionHash": "0xa21ef18e2d465f98d010dee13c7baeb2e693425e6b33b71a63b6d6daa44c2578", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0x64AcD4C418D911Baf2bb467Cb6DA9F75dDDd026E", - "transactionIndex": 152, + "contractAddress": "0x68cA4500a40A250E70cD99499B1dC27aB523882E", + "transactionIndex": 8, "gasUsed": "1584261", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0xb81ad0575e8db91453bc2682eae3ef0e5916e660f0a34882fe2e841563250512", - "transactionHash": "0x05f3fae480679a3697a88df836e10865ce069de665d479707c9b0da6777024a4", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000400000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0xc57d018fc99bbcc46619f240b147d8423995f0c932f1677449e24469acd730f0", + "transactionHash": "0xa21ef18e2d465f98d010dee13c7baeb2e693425e6b33b71a63b6d6daa44c2578", "logs": [ { - "transactionIndex": 152, - "blockNumber": 54803450, - "transactionHash": "0x05f3fae480679a3697a88df836e10865ce069de665d479707c9b0da6777024a4", + "transactionIndex": 8, + "blockNumber": 55572327, + "transactionHash": "0xa21ef18e2d465f98d010dee13c7baeb2e693425e6b33b71a63b6d6daa44c2578", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x0000000000000000000000007c7379531b2aee82e4ca06d4175d13b9cbeafd49" ], - "data": "0x00000000000000000000000000000000000000000000000000087150c3346b0000000000000000000000000000000000000000000000000267f273ceef67c1c3000000000000000000000000000000000000000000002436a018c1ed1276bcdd00000000000000000000000000000000000000000000000267ea027e2c3356c3000000000000000000000000000000000000000000002436a021333dd5ab27dd", - "logIndex": 1887, - "blockHash": "0xb81ad0575e8db91453bc2682eae3ef0e5916e660f0a34882fe2e841563250512" + "data": "0x00000000000000000000000000000000000000000000000000d32bb3c4b0344f000000000000000000000000000000000000000000000001d7eb6c56f36a763400000000000000000000000000000000000000000002e45838d1ac7927d6e463000000000000000000000000000000000000000000000001d71840a32eba41e500000000000000000000000000000000000000000002e45839a4d82cec8718b2", + "logIndex": 29, + "blockHash": "0xc57d018fc99bbcc46619f240b147d8423995f0c932f1677449e24469acd730f0" } ], - "blockNumber": 54803450, - "cumulativeGasUsed": "26934761", + "blockNumber": 55572327, + "cumulativeGasUsed": "2665077", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 5, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DEBTS_REBALANCE_IS_REQUIRED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_WITHDRAW_IS_REQUIRED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"totalAssets\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isUnderlyingA\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountA\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"debtAmountB\",\"type\":\"uint256\"},{\"internalType\":\"uint256[2]\",\"name\":\"pricesAB\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"decsAB\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"requiredLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"getAmountToReduceDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"deltaDebtAmountB\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"getAmountToReduceDebtForStrategy\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requiredAmountToReduceDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"}],\"name\":\"getLockedUnderlyingAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"estimatedUnderlyingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalAssets\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowedLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"isWithdrawByAggCallRequired\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getAmountToReduceDebt(uint256,bool,uint256,uint256,uint256[2],uint256[2],uint256)\":{\"params\":{\"collateralAmountA\":\"Total collateral amount in asset A\",\"debtAmountB\":\"Total debt amount in asset B\",\"decsAB\":\"10**decimals for A and B\",\"isUnderlyingA\":\"True if A is underlying\",\"pricesAB\":\"Prices of A and B, decimals 18\",\"requiredLockedAmountPercent\":\"Required value of locked amount percent [0..100]\",\"totalAssets\":\"Total assets of the strategy, in underlying\"},\"returns\":{\"deltaDebtAmountB\":\"The amount by which the debt should be reduced, asset B\"}},\"getAmountToReduceDebtForStrategy(address,uint256)\":{\"params\":{\"requiredAmountToReduceDebt\":\"If not zero: we are going to make repay-swap-repay to reduce total debt on the given amount. So, if possible it worth to make swap in such a way as to reduce the amount of debt by the given amount. This amount is set in terms of the token B if there is direct debt, or in terms of the token A otherwise.\",\"requiredLockedAmountPercent\":\"Required value of locked amount percent [0..100]\"}},\"getLockedUnderlyingAmount(address)\":{\"details\":\"We cannot call strategy.getState() because of stack too deep problem\",\"params\":{\"strategy_\":\"Instance of UniswapV3ConverterStrategy\"},\"returns\":{\"estimatedUnderlyingAmount\":\"Total locked amount recalculated to the underlying\",\"totalAssets\":\"strategy.totalAssets() - in terms of underlying\"}},\"isWithdrawByAggCallRequired(address,uint256)\":{\"params\":{\"allowedLockedAmountPercent\":\"[0...100]\",\"strategy_\":\"instance of IPairBasedStrategyReaderAccess\"},\"returns\":{\"_0\":\"0: it's not necessary to call withdrawByAgg 1: full withdraw is required (with propNotUnderlying = 0) 2: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DEBTS_REBALANCE_IS_REQUIRED()\":{\"notice\":\"Possible results of isWithdrawByAggCallRequired: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\"},\"FULL_WITHDRAW_IS_REQUIRED()\":{\"notice\":\"Possible results of isWithdrawByAggCallRequired: full withdraw is required (with propNotUnderlying = 0)\"},\"getAmountToReduceDebt(uint256,bool,uint256,uint256,uint256[2],uint256[2],uint256)\":{\"notice\":\"Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\"},\"getAmountToReduceDebtForStrategy(address,uint256)\":{\"notice\":\"Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\"},\"getLockedUnderlyingAmount(address)\":{\"notice\":\"Estimate amount of underlying locked in the strategy by TetuConverter\"},\"isWithdrawByAggCallRequired(address,uint256)\":{\"notice\":\"Check if a call of withdrawByAgg is required\"}},\"notice\":\"Read raw values and calculate complex values related to UniswapV3ConverterStrategy\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyReader.sol\":\"PairBasedStrategyReader\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedDefaultStateProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Provides access to getDefaultState() of a pair-based strategy\\r\\ninterface IPairBasedDefaultStateProvider {\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n );\\r\\n}\",\"keccak256\":\"0x883b0f9e463485a57aa1baea9aafef64180362d336114a53f6cb8b7a94303d70\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedStrategyReaderAccess.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./IPairBasedDefaultStateProvider.sol\\\";\\r\\n\\r\\n/// @notice Interface required to implement PairBasedStrategyReader\\r\\ninterface IPairBasedStrategyReaderAccess is IPairBasedDefaultStateProvider {\\r\\n function converter() external view returns (address);\\r\\n function splitter() external view returns (address);\\r\\n function totalAssets() external view returns (uint);\\r\\n function asset() external view returns (address);\\r\\n}\\r\\n\",\"keccak256\":\"0xec408e0b8d5923d9bd746f977b1ff0a47ee2b8e82fd29a18ce863049983e088c\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyReader.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"../../interfaces/IPairBasedStrategyReaderAccess.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\n\\r\\n/// @notice Read raw values and calculate complex values related to UniswapV3ConverterStrategy\\r\\ncontract PairBasedStrategyReader {\\r\\n\\r\\n /// @notice Possible results of isWithdrawByAggCallRequired:\\r\\n /// full withdraw is required (with propNotUnderlying = 0)\\r\\n uint constant public FULL_WITHDRAW_IS_REQUIRED = 1;\\r\\n /// @notice Possible results of isWithdrawByAggCallRequired:\\r\\n /// rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\\r\\n uint constant public DEBTS_REBALANCE_IS_REQUIRED = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct GetLockedUnderlyingAmountLocal {\\r\\n ITetuConverter converter;\\r\\n address[] tokens;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint directDebt;\\r\\n uint directCollateral;\\r\\n uint reverseDebt;\\r\\n uint reverseCollateral;\\r\\n uint directDebtCost;\\r\\n uint reverseCollateralCost;\\r\\n }\\r\\n\\r\\n struct GetAmountToReduceDebtLocal {\\r\\n address[] tokens;\\r\\n ITetuConverter converter;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n address[] addr;\\r\\n IPriceOracle priceOracle;\\r\\n uint debtAmountB;\\r\\n uint collateralAmountA;\\r\\n uint debtAmountA;\\r\\n uint collateralAmountB;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- Locked underlying amount logic\\r\\n /// @notice Estimate amount of underlying locked in the strategy by TetuConverter\\r\\n /// @dev We cannot call strategy.getState() because of stack too deep problem\\r\\n /// @param strategy_ Instance of UniswapV3ConverterStrategy\\r\\n /// @return estimatedUnderlyingAmount Total locked amount recalculated to the underlying\\r\\n /// @return totalAssets strategy.totalAssets() - in terms of underlying\\r\\n function getLockedUnderlyingAmount(address strategy_) public view returns (\\r\\n uint estimatedUnderlyingAmount,\\r\\n uint totalAssets\\r\\n ) {\\r\\n GetLockedUnderlyingAmountLocal memory v;\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (address[] memory addr, , , ) = strategy.getDefaultState();\\r\\n address tokenA = addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A];\\r\\n address tokenB = addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B];\\r\\n\\r\\n v.converter = ITetuConverter(strategy.converter());\\r\\n\\r\\n v.tokens = new address[](2);\\r\\n v.tokens[0] = ISplitter(strategy.splitter()).asset(); // underlying\\r\\n v.tokens[1] = tokenA == v.tokens[0] ? tokenB : tokenA; // not underlying\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(v.converter);\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, v.tokens, 2);\\r\\n\\r\\n // direct borrow: underlying is collateral\\r\\n (v.directDebt, v.directCollateral) = v.converter.getDebtAmountStored(strategy_, v.tokens[0], v.tokens[1], true);\\r\\n\\r\\n // reverse borrow: underlying is borrowed asset\\r\\n (v.reverseDebt, v.reverseCollateral) = v.converter.getDebtAmountStored(strategy_, v.tokens[1], v.tokens[0], true);\\r\\n\\r\\n v.directDebtCost = v.directDebt * v.prices[1] * v.decs[0] / v.decs[1] / v.prices[0];\\r\\n v.reverseCollateralCost = v.reverseCollateral * v.prices[1] * v.decs[0] / v.decs[1] / v.prices[0];\\r\\n\\r\\n return (\\r\\n v.directCollateral + v.reverseCollateralCost > (v.directDebtCost + v.reverseDebt)\\r\\n ? v.directCollateral + v.reverseCollateralCost - v.directDebtCost - v.reverseDebt\\r\\n : 0,\\r\\n strategy.totalAssets()\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Check if a call of withdrawByAgg is required\\r\\n /// @param strategy_ instance of IPairBasedStrategyReaderAccess\\r\\n /// @param allowedLockedAmountPercent [0...100]\\r\\n /// @return 0: it's not necessary to call withdrawByAgg\\r\\n /// 1: full withdraw is required (with propNotUnderlying = 0)\\r\\n /// 2: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\\r\\n function isWithdrawByAggCallRequired(address strategy_, uint allowedLockedAmountPercent) external view returns (\\r\\n uint\\r\\n ) {\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (, , uint[] memory nums, ) = strategy.getDefaultState();\\r\\n\\r\\n if (\\r\\n PairBasedStrategyLib.isFuseTriggeredOn(\\r\\n PairBasedStrategyLib.FuseStatus(nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS])\\r\\n )\\r\\n ) {\\r\\n // fuse is enabled: full withdraw to underlying is required\\r\\n if (nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] == 0) {\\r\\n return FULL_WITHDRAW_IS_REQUIRED;\\r\\n }\\r\\n } else {\\r\\n // locked amount is too high: partial withdraw (with pool proportions) is required\\r\\n (uint estimatedUnderlyingAmount, uint totalAssets) = getLockedUnderlyingAmount(strategy_);\\r\\n uint percent = estimatedUnderlyingAmount * 100 / totalAssets;\\r\\n\\r\\n if (percent > allowedLockedAmountPercent) {\\r\\n return DEBTS_REBALANCE_IS_REQUIRED;\\r\\n }\\r\\n }\\r\\n\\r\\n return 0;\\r\\n }\\r\\n //endregion -------------------------------------------------- Locked underlying amount logic\\r\\n\\r\\n //region -------------------------------------------------- Calculate amount to reduce debt\\r\\n /// @notice Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\\r\\n /// @param requiredLockedAmountPercent Required value of locked amount percent [0..100]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n /// This amount is set in terms of the token B if there is direct debt, or in terms of the token A otherwise.\\r\\n function getAmountToReduceDebtForStrategy(address strategy_, uint requiredLockedAmountPercent) external view returns (\\r\\n uint requiredAmountToReduceDebt\\r\\n ) {\\r\\n GetAmountToReduceDebtLocal memory v;\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (v.addr, , , ) = strategy.getDefaultState();\\r\\n\\r\\n v.tokens = new address[](2);\\r\\n v.tokens[0] = v.addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A];\\r\\n v.tokens[1] = v.addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B];\\r\\n\\r\\n v.converter = ITetuConverter(strategy.converter());\\r\\n\\r\\n v.priceOracle = AppLib._getPriceOracle(v.converter);\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(v.priceOracle, v.tokens, 2);\\r\\n\\r\\n (v.debtAmountB, v.collateralAmountA) = v.converter.getDebtAmountStored(strategy_, v.tokens[0], v.tokens[1], false);\\r\\n (v.debtAmountA, v.collateralAmountB) = v.converter.getDebtAmountStored(strategy_, v.tokens[1], v.tokens[0], false);\\r\\n\\r\\n // the app should have debt in one direction only - either direct or reverse\\r\\n // but dust debts in contrary direction are still possible\\r\\n if (v.debtAmountB > v.collateralAmountB) {\\r\\n if (v.debtAmountB > AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // there is direct debt\\r\\n requiredAmountToReduceDebt = getAmountToReduceDebt(\\r\\n strategy.totalAssets(),\\r\\n strategy.asset() == v.tokens[0],\\r\\n v.collateralAmountA,\\r\\n v.debtAmountB,\\r\\n [v.prices[0], v.prices[1]],\\r\\n [v.decs[0], v.decs[1]],\\r\\n requiredLockedAmountPercent\\r\\n );\\r\\n }\\r\\n } else {\\r\\n if (v.debtAmountA > AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // there is reverse debt\\r\\n requiredAmountToReduceDebt = getAmountToReduceDebt(\\r\\n strategy.totalAssets(),\\r\\n strategy.asset() == v.tokens[1],\\r\\n v.collateralAmountB,\\r\\n v.debtAmountA,\\r\\n [v.prices[1], v.prices[0]],\\r\\n [v.decs[1], v.decs[0]],\\r\\n requiredLockedAmountPercent\\r\\n );\\r\\n }\\r\\n }\\r\\n return requiredAmountToReduceDebt;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\\r\\n /// @param totalAssets Total assets of the strategy, in underlying\\r\\n /// @param isUnderlyingA True if A is underlying\\r\\n /// @param collateralAmountA Total collateral amount in asset A\\r\\n /// @param debtAmountB Total debt amount in asset B\\r\\n /// @param pricesAB Prices of A and B, decimals 18\\r\\n /// @param decsAB 10**decimals for A and B\\r\\n /// @param requiredLockedAmountPercent Required value of locked amount percent [0..100]\\r\\n /// @return deltaDebtAmountB The amount by which the debt should be reduced, asset B\\r\\n function getAmountToReduceDebt(\\r\\n uint totalAssets,\\r\\n bool isUnderlyingA,\\r\\n uint collateralAmountA,\\r\\n uint debtAmountB,\\r\\n uint[2] memory pricesAB,\\r\\n uint[2] memory decsAB,\\r\\n uint requiredLockedAmountPercent\\r\\n ) public pure returns (uint deltaDebtAmountB) {\\r\\n if (debtAmountB != 0 && totalAssets != 0) {\\r\\n uint alpha18 = 1e18 * collateralAmountA * decsAB[1] / decsAB[0] / debtAmountB;\\r\\n\\r\\n uint indexUnderlying = isUnderlyingA ? 0 : 1;\\r\\n uint lockedPercent18 = 1e18\\r\\n * AppLib.sub0(collateralAmountA * pricesAB[0] / decsAB[0], debtAmountB * pricesAB[1] / decsAB[1])\\r\\n / (totalAssets * pricesAB[indexUnderlying] / decsAB[indexUnderlying]);\\r\\n uint delta = AppLib.sub0(alpha18 * pricesAB[0] / 1e18, pricesAB[1]);\\r\\n\\r\\n deltaDebtAmountB = delta == 0\\r\\n ? 0 // weird case\\r\\n : AppLib.sub0(lockedPercent18, requiredLockedAmountPercent * 1e16)\\r\\n * totalAssets\\r\\n * pricesAB[indexUnderlying]\\r\\n / decsAB[indexUnderlying]\\r\\n / delta;\\r\\n }\\r\\n\\r\\n return deltaDebtAmountB * decsAB[1] / 1e18;\\r\\n }\\r\\n //endregion -------------------------------------------------- Calculate amount to reduce debt\\r\\n}\\r\\n\",\"keccak256\":\"0x6a02b56f946a2db1ffca47387ba6a06cf50d5f8693b5a08ee703c8fbb02cb0e2\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x608060405234801561001057600080fd5b50611bb2806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c8063369e2efc1461006757806359af44dc146100945780635d698b52146100aa578063e8405269146100b2578063ebe4aef2146100c5578063fe03683f146100d8575b600080fd5b61007a610075366004611557565b6100eb565b604080519283526020830191909152015b60405180910390f35b61009c600181565b60405190815260200161008b565b61009c600281565b61009c6100c0366004611639565b6107d4565b61009c6100d33660046116a9565b6109c5565b61009c6100e63660046116a9565b61110f565b60008061014d60405180610140016040528060006001600160a01b031681526020016060815260200160608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008490506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610192573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ba9190810190611833565b50505090506000816000815181106101d4576101d4611941565b602002602001015190506000826001815181106101f3576101f3611941565b60200260200101519050836001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f9190611957565b6001600160a01b031685526040805160028082526060820183529091602083019080368337019050508560200181905250836001600160a01b0316633cd8045e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f29190611957565b6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611957565b856020015160008151811061036a5761036a611941565b6001600160a01b03909216602092830291909101820152850151805160009061039557610395611941565b60200260200101516001600160a01b0316826001600160a01b0316146103bb57816103bd565b805b85602001516001815181106103d4576103d4611941565b60200260200101906001600160a01b031690816001600160a01b0316815250506000610403866000015161123d565b90506104158187602001516002611302565b606088015260408701528551602087015180516001600160a01b039092169163e4c2be70918c9160009061044b5761044b611941565b6020026020010151896020015160018151811061046a5761046a611941565b602002602001015160016040518563ffffffff1660e01b81526004016104939493929190611974565b6040805180830381865afa1580156104af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d3919061199e565b60a088015260808701528551602087015180516001600160a01b039092169163e4c2be70918c91600190811061050b5761050b611941565b6020026020010151896020015160008151811061052a5761052a611941565b602002602001015160016040518563ffffffff1660e01b81526004016105539493929190611974565b6040805180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061199e565b60e088015260c0870152604086015180516000906105b3576105b3611941565b602002602001015186606001516001815181106105d2576105d2611941565b602002602001015187606001516000815181106105f1576105f1611941565b6020026020010151886040015160018151811061061057610610611941565b6020026020010151896080015161062791906119d8565b61063191906119d8565b61063b91906119ef565b61064591906119ef565b6101008701526040860151805160009061066157610661611941565b6020026020010151866060015160018151811061068057610680611941565b6020026020010151876060015160008151811061069f5761069f611941565b602002602001015188604001516001815181106106be576106be611941565b60200260200101518960e001516106d591906119d8565b6106df91906119d8565b6106e991906119ef565b6106f391906119ef565b61012087015260c086015161010087015161070e9190611a11565b8661012001518760a001516107239190611a11565b1161072f576000610763565b8560c001518661010001518761012001518860a0015161074f9190611a11565b6107599190611a24565b6107639190611a24565b856001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190611a37565b97509750505050505050915091565b600084158015906107e457508715155b15610996578251602084015160009187916108078a670de0b6b3a76400006119d8565b61081191906119d8565b61081b91906119ef565b61082591906119ef565b9050600088610835576001610838565b60005b60ff169050600085826002811061085157610851611941565b602002015187836002811061086857610868611941565b6020020151610877908d6119d8565b61088191906119ef565b865188516108c19190610894908d6119d8565b61089e91906119ef565b6020808a0151908b01516108b2908d6119d8565b6108bc91906119ef565b611501565b6108d390670de0b6b3a76400006119d8565b6108dd91906119ef565b90506000610912670de0b6b3a7640000898360200201516108fe90876119d8565b61090891906119ef565b60208a0151611501565b9050801561098c578087846002811061092d5761092d611941565b602002015189856002811061094457610944611941565b60200201518e61095f866108bc8c662386f26fc100006119d8565b61096991906119d8565b61097391906119d8565b61097d91906119ef565b61098791906119ef565b61098f565b60005b9450505050505b6020830151670de0b6b3a7640000906109af90836119d8565b6109b991906119ef565b98975050505050505050565b6000610a2f6040518061014001604052806060815260200160006001600160a01b0316815260200160608152602001606081526020016060815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6000849050806001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9a9190810190611833565b50505060808301526040805160028082526060820183529091602083019080368337505050825260808201518051600090610ad757610ad7611941565b60200260200101518260000151600081518110610af657610af6611941565b60200260200101906001600160a01b031690816001600160a01b0316815250508160800151600181518110610b2d57610b2d611941565b60200260200101518260000151600181518110610b4c57610b4c611941565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bce9190611957565b6001600160a01b031660208301819052610be79061123d565b6001600160a01b031660a083018190528251610c0591906002611302565b606084015260408301526020820151825180516001600160a01b039092169163e4c2be70918891600090610c3b57610c3b611941565b60200260200101518560000151600181518110610c5a57610c5a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610c839493929190611974565b6040805180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc3919061199e565b60e084015260c08301526020820151825180516001600160a01b039092169163e4c2be709188916001908110610cfb57610cfb611941565b60200260200101518560000151600081518110610d1a57610d1a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610d439493929190611974565b6040805180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d83919061199e565b610120840181905261010084019190915260c08301511115610f5b5760648260c001511115610f5657610f53816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ded573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e119190611a37565b83518051600090610e2457610e24611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190611957565b6001600160a01b0316148460e001518560c0015160405180604001604052808860400151600081518110610ecd57610ecd611941565b602002602001015181526020018860400151600181518110610ef157610ef1611941565b602002602001015181525060405180604001604052808960600151600081518110610f1e57610f1e611941565b602002602001015181526020018960600151600181518110610f4257610f42611941565b60200260200101518152508a6107d4565b92505b611106565b6064826101000151111561110657611103816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fce9190611a37565b835180516001908110610fe357610fe3611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110569190611957565b6001600160a01b0316148461012001518561010001516040518060400160405280886040015160018151811061108e5761108e611941565b6020026020010151815260200188604001516000815181106110b2576110b2611941565b6020026020010151815250604051806040016040528089606001516001815181106110df576110df611941565b602002602001015181526020018960600151600081518110610f4257610f42611941565b92505b50505b92915050565b6000808390506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261117d9190810190611833565b50925050506111b68160018151811061119857611198611941565b602002602001015160038111156111b1576111b1611a50565b611522565b156111ed57806003815181106111ce576111ce611941565b60200260200101516000036111e857600192505050611109565b611232565b6000806111f9876100eb565b909250905060008161120c8460646119d8565b61121691906119ef565b90508681111561122e57600295505050505050611109565b5050505b506000949350505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a19190611957565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190611957565b6060808267ffffffffffffffff81111561131e5761131e611582565b604051908082528060200260200182016040528015611347578160200160208202803683370190505b5091508267ffffffffffffffff81111561136357611363611582565b60405190808252806020026020018201604052801561138c578160200160208202803683370190505b50905060005b838110156114f8578481815181106113ac576113ac611941565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190611a66565b61142090600a611b6d565b82828151811061143257611432611941565b602002602001018181525050856001600160a01b031663b3596f0786838151811061145f5761145f611941565b60200260200101516040518263ffffffff1660e01b815260040161149291906001600160a01b0391909116815260200190565b602060405180830381865afa1580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190611a37565b8382815181106114e5576114e5611941565b6020908102919091010152600101611392565b50935093915050565b600081831161151157600061151b565b61151b8284611a24565b9392505050565b6000600182600381111561153857611538611a50565b1192915050565b6001600160a01b038116811461155457600080fd5b50565b60006020828403121561156957600080fd5b813561151b8161153f565b801515811461155457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c1576115c1611582565b604052919050565b600082601f8301126115da57600080fd5b6040516040810181811067ffffffffffffffff821117156115fd576115fd611582565b806040525080604084018581111561161457600080fd5b845b8181101561162e578035835260209283019201611616565b509195945050505050565b6000806000806000806000610120888a03121561165557600080fd5b87359650602088013561166781611574565b955060408801359450606088013593506116848960808a016115c9565b92506116938960c08a016115c9565b9150610100880135905092959891949750929550565b600080604083850312156116bc57600080fd5b82356116c78161153f565b946020939093013593505050565b600067ffffffffffffffff8211156116ef576116ef611582565b5060051b60200190565b600082601f83011261170a57600080fd5b8151602061171f61171a836116d5565b611598565b82815260059290921b8401810191818101908684111561173e57600080fd5b8286015b848110156117695780518060020b811461175c5760008081fd5b8352918301918301611742565b509695505050505050565b600082601f83011261178557600080fd5b8151602061179561171a836116d5565b82815260059290921b840181019181810190868411156117b457600080fd5b8286015b8481101561176957805183529183019183016117b8565b600082601f8301126117e057600080fd5b815160206117f061171a836116d5565b82815260059290921b8401810191818101908684111561180f57600080fd5b8286015b8481101561176957805161182681611574565b8352918301918301611813565b6000806000806080858703121561184957600080fd5b845167ffffffffffffffff8082111561186157600080fd5b818701915087601f83011261187557600080fd5b8151602061188561171a836116d5565b82815260059290921b8401810191818101908b8411156118a457600080fd5b948201945b838610156118cb5785516118bc8161153f565b825294820194908201906118a9565b918a01519198509093505050808211156118e457600080fd5b6118f0888389016116f9565b9450604087015191508082111561190657600080fd5b61191288838901611774565b9350606087015191508082111561192857600080fd5b50611935878288016117cf565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561196957600080fd5b815161151b8161153f565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b600080604083850312156119b157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611109576111096119c2565b600082611a0c57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611109576111096119c2565b81810381811115611109576111096119c2565b600060208284031215611a4957600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215611a7857600080fd5b815160ff8116811461151b57600080fd5b600181815b80851115611ac4578160001904821115611aaa57611aaa6119c2565b80851615611ab757918102915b93841c9390800290611a8e565b509250929050565b600082611adb57506001611109565b81611ae857506000611109565b8160018114611afe5760028114611b0857611b24565b6001915050611109565b60ff841115611b1957611b196119c2565b50506001821b611109565b5060208310610133831016604e8410600b8410161715611b47575081810a611109565b611b518383611a89565b8060001904821115611b6557611b656119c2565b029392505050565b600061151b60ff841683611acc56fea264697066735822122052c486d10d79048ea7c29a18cd855e7aa9add0f68d15956290ff8d5f5890426864736f6c63430008110033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063369e2efc1461006757806359af44dc146100945780635d698b52146100aa578063e8405269146100b2578063ebe4aef2146100c5578063fe03683f146100d8575b600080fd5b61007a610075366004611557565b6100eb565b604080519283526020830191909152015b60405180910390f35b61009c600181565b60405190815260200161008b565b61009c600281565b61009c6100c0366004611639565b6107d4565b61009c6100d33660046116a9565b6109c5565b61009c6100e63660046116a9565b61110f565b60008061014d60405180610140016040528060006001600160a01b031681526020016060815260200160608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008490506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610192573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ba9190810190611833565b50505090506000816000815181106101d4576101d4611941565b602002602001015190506000826001815181106101f3576101f3611941565b60200260200101519050836001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f9190611957565b6001600160a01b031685526040805160028082526060820183529091602083019080368337019050508560200181905250836001600160a01b0316633cd8045e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f29190611957565b6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611957565b856020015160008151811061036a5761036a611941565b6001600160a01b03909216602092830291909101820152850151805160009061039557610395611941565b60200260200101516001600160a01b0316826001600160a01b0316146103bb57816103bd565b805b85602001516001815181106103d4576103d4611941565b60200260200101906001600160a01b031690816001600160a01b0316815250506000610403866000015161123d565b90506104158187602001516002611302565b606088015260408701528551602087015180516001600160a01b039092169163e4c2be70918c9160009061044b5761044b611941565b6020026020010151896020015160018151811061046a5761046a611941565b602002602001015160016040518563ffffffff1660e01b81526004016104939493929190611974565b6040805180830381865afa1580156104af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d3919061199e565b60a088015260808701528551602087015180516001600160a01b039092169163e4c2be70918c91600190811061050b5761050b611941565b6020026020010151896020015160008151811061052a5761052a611941565b602002602001015160016040518563ffffffff1660e01b81526004016105539493929190611974565b6040805180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061199e565b60e088015260c0870152604086015180516000906105b3576105b3611941565b602002602001015186606001516001815181106105d2576105d2611941565b602002602001015187606001516000815181106105f1576105f1611941565b6020026020010151886040015160018151811061061057610610611941565b6020026020010151896080015161062791906119d8565b61063191906119d8565b61063b91906119ef565b61064591906119ef565b6101008701526040860151805160009061066157610661611941565b6020026020010151866060015160018151811061068057610680611941565b6020026020010151876060015160008151811061069f5761069f611941565b602002602001015188604001516001815181106106be576106be611941565b60200260200101518960e001516106d591906119d8565b6106df91906119d8565b6106e991906119ef565b6106f391906119ef565b61012087015260c086015161010087015161070e9190611a11565b8661012001518760a001516107239190611a11565b1161072f576000610763565b8560c001518661010001518761012001518860a0015161074f9190611a11565b6107599190611a24565b6107639190611a24565b856001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190611a37565b97509750505050505050915091565b600084158015906107e457508715155b15610996578251602084015160009187916108078a670de0b6b3a76400006119d8565b61081191906119d8565b61081b91906119ef565b61082591906119ef565b9050600088610835576001610838565b60005b60ff169050600085826002811061085157610851611941565b602002015187836002811061086857610868611941565b6020020151610877908d6119d8565b61088191906119ef565b865188516108c19190610894908d6119d8565b61089e91906119ef565b6020808a0151908b01516108b2908d6119d8565b6108bc91906119ef565b611501565b6108d390670de0b6b3a76400006119d8565b6108dd91906119ef565b90506000610912670de0b6b3a7640000898360200201516108fe90876119d8565b61090891906119ef565b60208a0151611501565b9050801561098c578087846002811061092d5761092d611941565b602002015189856002811061094457610944611941565b60200201518e61095f866108bc8c662386f26fc100006119d8565b61096991906119d8565b61097391906119d8565b61097d91906119ef565b61098791906119ef565b61098f565b60005b9450505050505b6020830151670de0b6b3a7640000906109af90836119d8565b6109b991906119ef565b98975050505050505050565b6000610a2f6040518061014001604052806060815260200160006001600160a01b0316815260200160608152602001606081526020016060815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6000849050806001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9a9190810190611833565b50505060808301526040805160028082526060820183529091602083019080368337505050825260808201518051600090610ad757610ad7611941565b60200260200101518260000151600081518110610af657610af6611941565b60200260200101906001600160a01b031690816001600160a01b0316815250508160800151600181518110610b2d57610b2d611941565b60200260200101518260000151600181518110610b4c57610b4c611941565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bce9190611957565b6001600160a01b031660208301819052610be79061123d565b6001600160a01b031660a083018190528251610c0591906002611302565b606084015260408301526020820151825180516001600160a01b039092169163e4c2be70918891600090610c3b57610c3b611941565b60200260200101518560000151600181518110610c5a57610c5a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610c839493929190611974565b6040805180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc3919061199e565b60e084015260c08301526020820151825180516001600160a01b039092169163e4c2be709188916001908110610cfb57610cfb611941565b60200260200101518560000151600081518110610d1a57610d1a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610d439493929190611974565b6040805180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d83919061199e565b610120840181905261010084019190915260c08301511115610f5b5760648260c001511115610f5657610f53816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ded573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e119190611a37565b83518051600090610e2457610e24611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190611957565b6001600160a01b0316148460e001518560c0015160405180604001604052808860400151600081518110610ecd57610ecd611941565b602002602001015181526020018860400151600181518110610ef157610ef1611941565b602002602001015181525060405180604001604052808960600151600081518110610f1e57610f1e611941565b602002602001015181526020018960600151600181518110610f4257610f42611941565b60200260200101518152508a6107d4565b92505b611106565b6064826101000151111561110657611103816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fce9190611a37565b835180516001908110610fe357610fe3611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110569190611957565b6001600160a01b0316148461012001518561010001516040518060400160405280886040015160018151811061108e5761108e611941565b6020026020010151815260200188604001516000815181106110b2576110b2611941565b6020026020010151815250604051806040016040528089606001516001815181106110df576110df611941565b602002602001015181526020018960600151600081518110610f4257610f42611941565b92505b50505b92915050565b6000808390506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261117d9190810190611833565b50925050506111b68160018151811061119857611198611941565b602002602001015160038111156111b1576111b1611a50565b611522565b156111ed57806003815181106111ce576111ce611941565b60200260200101516000036111e857600192505050611109565b611232565b6000806111f9876100eb565b909250905060008161120c8460646119d8565b61121691906119ef565b90508681111561122e57600295505050505050611109565b5050505b506000949350505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a19190611957565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190611957565b6060808267ffffffffffffffff81111561131e5761131e611582565b604051908082528060200260200182016040528015611347578160200160208202803683370190505b5091508267ffffffffffffffff81111561136357611363611582565b60405190808252806020026020018201604052801561138c578160200160208202803683370190505b50905060005b838110156114f8578481815181106113ac576113ac611941565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190611a66565b61142090600a611b6d565b82828151811061143257611432611941565b602002602001018181525050856001600160a01b031663b3596f0786838151811061145f5761145f611941565b60200260200101516040518263ffffffff1660e01b815260040161149291906001600160a01b0391909116815260200190565b602060405180830381865afa1580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190611a37565b8382815181106114e5576114e5611941565b6020908102919091010152600101611392565b50935093915050565b600081831161151157600061151b565b61151b8284611a24565b9392505050565b6000600182600381111561153857611538611a50565b1192915050565b6001600160a01b038116811461155457600080fd5b50565b60006020828403121561156957600080fd5b813561151b8161153f565b801515811461155457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c1576115c1611582565b604052919050565b600082601f8301126115da57600080fd5b6040516040810181811067ffffffffffffffff821117156115fd576115fd611582565b806040525080604084018581111561161457600080fd5b845b8181101561162e578035835260209283019201611616565b509195945050505050565b6000806000806000806000610120888a03121561165557600080fd5b87359650602088013561166781611574565b955060408801359450606088013593506116848960808a016115c9565b92506116938960c08a016115c9565b9150610100880135905092959891949750929550565b600080604083850312156116bc57600080fd5b82356116c78161153f565b946020939093013593505050565b600067ffffffffffffffff8211156116ef576116ef611582565b5060051b60200190565b600082601f83011261170a57600080fd5b8151602061171f61171a836116d5565b611598565b82815260059290921b8401810191818101908684111561173e57600080fd5b8286015b848110156117695780518060020b811461175c5760008081fd5b8352918301918301611742565b509695505050505050565b600082601f83011261178557600080fd5b8151602061179561171a836116d5565b82815260059290921b840181019181810190868411156117b457600080fd5b8286015b8481101561176957805183529183019183016117b8565b600082601f8301126117e057600080fd5b815160206117f061171a836116d5565b82815260059290921b8401810191818101908684111561180f57600080fd5b8286015b8481101561176957805161182681611574565b8352918301918301611813565b6000806000806080858703121561184957600080fd5b845167ffffffffffffffff8082111561186157600080fd5b818701915087601f83011261187557600080fd5b8151602061188561171a836116d5565b82815260059290921b8401810191818101908b8411156118a457600080fd5b948201945b838610156118cb5785516118bc8161153f565b825294820194908201906118a9565b918a01519198509093505050808211156118e457600080fd5b6118f0888389016116f9565b9450604087015191508082111561190657600080fd5b61191288838901611774565b9350606087015191508082111561192857600080fd5b50611935878288016117cf565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561196957600080fd5b815161151b8161153f565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b600080604083850312156119b157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611109576111096119c2565b600082611a0c57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611109576111096119c2565b81810381811115611109576111096119c2565b600060208284031215611a4957600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215611a7857600080fd5b815160ff8116811461151b57600080fd5b600181815b80851115611ac4578160001904821115611aaa57611aaa6119c2565b80851615611ab757918102915b93841c9390800290611a8e565b509250929050565b600082611adb57506001611109565b81611ae857506000611109565b8160018114611afe5760028114611b0857611b24565b6001915050611109565b60ff841115611b1957611b196119c2565b50506001821b611109565b5060208310610133831016604e8410600b8410161715611b47575081810a611109565b611b518383611a89565b8060001904821115611b6557611b656119c2565b029392505050565b600061151b60ff841683611acc56fea264697066735822122052c486d10d79048ea7c29a18cd855e7aa9add0f68d15956290ff8d5f5890426864736f6c63430008110033", + "numDeployments": 6, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DEBTS_REBALANCE_IS_REQUIRED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FULL_WITHDRAW_IS_REQUIRED\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"totalAssets\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isUnderlyingA\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"collateralAmountA\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"debtAmountB\",\"type\":\"uint256\"},{\"internalType\":\"uint256[2]\",\"name\":\"pricesAB\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256[2]\",\"name\":\"decsAB\",\"type\":\"uint256[2]\"},{\"internalType\":\"uint256\",\"name\":\"requiredLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"getAmountToReduceDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"deltaDebtAmountB\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"requiredLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"getAmountToReduceDebtForStrategy\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"requiredAmountToReduceDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"}],\"name\":\"getLockedUnderlyingAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"estimatedUnderlyingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalAssets\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategy_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowedLockedAmountPercent\",\"type\":\"uint256\"}],\"name\":\"isWithdrawByAggCallRequired\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getAmountToReduceDebt(uint256,bool,uint256,uint256,uint256[2],uint256[2],uint256)\":{\"params\":{\"collateralAmountA\":\"Total collateral amount in asset A\",\"debtAmountB\":\"Total debt amount in asset B\",\"decsAB\":\"10**decimals for A and B\",\"isUnderlyingA\":\"True if A is underlying\",\"pricesAB\":\"Prices of A and B, decimals 18\",\"requiredLockedAmountPercent\":\"Required value of locked amount percent [0..100]\",\"totalAssets\":\"Total assets of the strategy, in underlying\"},\"returns\":{\"deltaDebtAmountB\":\"The amount by which the debt should be reduced, asset B\"}},\"getAmountToReduceDebtForStrategy(address,uint256)\":{\"params\":{\"requiredAmountToReduceDebt\":\"If not zero: we are going to make repay-swap-repay to reduce total debt on the given amount. So, if possible it worth to make swap in such a way as to reduce the amount of debt by the given amount. This amount is set in terms of the token B if there is direct debt, or in terms of the token A otherwise.\",\"requiredLockedAmountPercent\":\"Required value of locked amount percent [0..100]\"}},\"getLockedUnderlyingAmount(address)\":{\"details\":\"We cannot call strategy.getState() because of stack too deep problem\",\"params\":{\"strategy_\":\"Instance of UniswapV3ConverterStrategy\"},\"returns\":{\"estimatedUnderlyingAmount\":\"Total locked amount recalculated to the underlying\",\"totalAssets\":\"strategy.totalAssets() - in terms of underlying\"}},\"isWithdrawByAggCallRequired(address,uint256)\":{\"params\":{\"allowedLockedAmountPercent\":\"[0...100]\",\"strategy_\":\"instance of IPairBasedStrategyReaderAccess\"},\"returns\":{\"_0\":\"0: it's not necessary to call withdrawByAgg 1: full withdraw is required (with propNotUnderlying = 0) 2: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DEBTS_REBALANCE_IS_REQUIRED()\":{\"notice\":\"Possible results of isWithdrawByAggCallRequired: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\"},\"FULL_WITHDRAW_IS_REQUIRED()\":{\"notice\":\"Possible results of isWithdrawByAggCallRequired: full withdraw is required (with propNotUnderlying = 0)\"},\"getAmountToReduceDebt(uint256,bool,uint256,uint256,uint256[2],uint256[2],uint256)\":{\"notice\":\"Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\"},\"getAmountToReduceDebtForStrategy(address,uint256)\":{\"notice\":\"Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\"},\"getLockedUnderlyingAmount(address)\":{\"notice\":\"Estimate amount of underlying locked in the strategy by TetuConverter\"},\"isWithdrawByAggCallRequired(address,uint256)\":{\"notice\":\"Check if a call of withdrawByAgg is required\"}},\"notice\":\"Read raw values and calculate complex values related to UniswapV3ConverterStrategy\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/pair/PairBasedStrategyReader.sol\":\"PairBasedStrategyReader\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedDefaultStateProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Provides access to getDefaultState() of a pair-based strategy\\r\\ninterface IPairBasedDefaultStateProvider {\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n );\\r\\n}\",\"keccak256\":\"0x883b0f9e463485a57aa1baea9aafef64180362d336114a53f6cb8b7a94303d70\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedStrategyReaderAccess.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./IPairBasedDefaultStateProvider.sol\\\";\\r\\n\\r\\n/// @notice Interface required to implement PairBasedStrategyReader\\r\\ninterface IPairBasedStrategyReaderAccess is IPairBasedDefaultStateProvider {\\r\\n function converter() external view returns (address);\\r\\n function splitter() external view returns (address);\\r\\n function totalAssets() external view returns (uint);\\r\\n function asset() external view returns (address);\\r\\n}\\r\\n\",\"keccak256\":\"0xec408e0b8d5923d9bd746f977b1ff0a47ee2b8e82fd29a18ce863049983e088c\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyReader.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"../../interfaces/IPairBasedStrategyReaderAccess.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\n\\r\\n/// @notice Read raw values and calculate complex values related to UniswapV3ConverterStrategy\\r\\ncontract PairBasedStrategyReader {\\r\\n\\r\\n /// @notice Possible results of isWithdrawByAggCallRequired:\\r\\n /// full withdraw is required (with propNotUnderlying = 0)\\r\\n uint constant public FULL_WITHDRAW_IS_REQUIRED = 1;\\r\\n /// @notice Possible results of isWithdrawByAggCallRequired:\\r\\n /// rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\\r\\n uint constant public DEBTS_REBALANCE_IS_REQUIRED = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct GetLockedUnderlyingAmountLocal {\\r\\n ITetuConverter converter;\\r\\n address[] tokens;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint directDebt;\\r\\n uint directCollateral;\\r\\n uint reverseDebt;\\r\\n uint reverseCollateral;\\r\\n uint directDebtCost;\\r\\n uint reverseCollateralCost;\\r\\n }\\r\\n\\r\\n struct GetAmountToReduceDebtLocal {\\r\\n address[] tokens;\\r\\n ITetuConverter converter;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n address[] addr;\\r\\n IPriceOracle priceOracle;\\r\\n uint debtAmountB;\\r\\n uint collateralAmountA;\\r\\n uint debtAmountA;\\r\\n uint collateralAmountB;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- Locked underlying amount logic\\r\\n /// @notice Estimate amount of underlying locked in the strategy by TetuConverter\\r\\n /// @dev We cannot call strategy.getState() because of stack too deep problem\\r\\n /// @param strategy_ Instance of UniswapV3ConverterStrategy\\r\\n /// @return estimatedUnderlyingAmount Total locked amount recalculated to the underlying\\r\\n /// @return totalAssets strategy.totalAssets() - in terms of underlying\\r\\n function getLockedUnderlyingAmount(address strategy_) public view returns (\\r\\n uint estimatedUnderlyingAmount,\\r\\n uint totalAssets\\r\\n ) {\\r\\n GetLockedUnderlyingAmountLocal memory v;\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (address[] memory addr, , , ) = strategy.getDefaultState();\\r\\n address tokenA = addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A];\\r\\n address tokenB = addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B];\\r\\n\\r\\n v.converter = ITetuConverter(strategy.converter());\\r\\n\\r\\n v.tokens = new address[](2);\\r\\n v.tokens[0] = ISplitter(strategy.splitter()).asset(); // underlying\\r\\n v.tokens[1] = tokenA == v.tokens[0] ? tokenB : tokenA; // not underlying\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(v.converter);\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, v.tokens, 2);\\r\\n\\r\\n // direct borrow: underlying is collateral\\r\\n (v.directDebt, v.directCollateral) = v.converter.getDebtAmountStored(strategy_, v.tokens[0], v.tokens[1], true);\\r\\n\\r\\n // reverse borrow: underlying is borrowed asset\\r\\n (v.reverseDebt, v.reverseCollateral) = v.converter.getDebtAmountStored(strategy_, v.tokens[1], v.tokens[0], true);\\r\\n\\r\\n v.directDebtCost = v.directDebt * v.prices[1] * v.decs[0] / v.decs[1] / v.prices[0];\\r\\n v.reverseCollateralCost = v.reverseCollateral * v.prices[1] * v.decs[0] / v.decs[1] / v.prices[0];\\r\\n\\r\\n return (\\r\\n v.directCollateral + v.reverseCollateralCost > (v.directDebtCost + v.reverseDebt)\\r\\n ? v.directCollateral + v.reverseCollateralCost - v.directDebtCost - v.reverseDebt\\r\\n : 0,\\r\\n strategy.totalAssets()\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Check if a call of withdrawByAgg is required\\r\\n /// @param strategy_ instance of IPairBasedStrategyReaderAccess\\r\\n /// @param allowedLockedAmountPercent [0...100]\\r\\n /// @return 0: it's not necessary to call withdrawByAgg\\r\\n /// 1: full withdraw is required (with propNotUnderlying = 0)\\r\\n /// 2: rebalance of the debts is required with pool proportions (propNotUnderlying = type(uint).max)\\r\\n function isWithdrawByAggCallRequired(address strategy_, uint allowedLockedAmountPercent) external view returns (\\r\\n uint\\r\\n ) {\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (, , uint[] memory nums, ) = strategy.getDefaultState();\\r\\n\\r\\n if (\\r\\n PairBasedStrategyLib.isFuseTriggeredOn(\\r\\n PairBasedStrategyLib.FuseStatus(nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS])\\r\\n )\\r\\n ) {\\r\\n // fuse is enabled: full withdraw to underlying is required\\r\\n if (nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] == 0) {\\r\\n return FULL_WITHDRAW_IS_REQUIRED;\\r\\n }\\r\\n } else {\\r\\n // locked amount is too high: partial withdraw (with pool proportions) is required\\r\\n (uint estimatedUnderlyingAmount, uint totalAssets) = getLockedUnderlyingAmount(strategy_);\\r\\n uint percent = estimatedUnderlyingAmount * 100 / totalAssets;\\r\\n\\r\\n if (percent > allowedLockedAmountPercent) {\\r\\n return DEBTS_REBALANCE_IS_REQUIRED;\\r\\n }\\r\\n }\\r\\n\\r\\n return 0;\\r\\n }\\r\\n //endregion -------------------------------------------------- Locked underlying amount logic\\r\\n\\r\\n //region -------------------------------------------------- Calculate amount to reduce debt\\r\\n /// @notice Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\\r\\n /// @param requiredLockedAmountPercent Required value of locked amount percent [0..100]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n /// This amount is set in terms of the token B if there is direct debt, or in terms of the token A otherwise.\\r\\n function getAmountToReduceDebtForStrategy(address strategy_, uint requiredLockedAmountPercent) external view returns (\\r\\n uint requiredAmountToReduceDebt\\r\\n ) {\\r\\n GetAmountToReduceDebtLocal memory v;\\r\\n IPairBasedStrategyReaderAccess strategy = IPairBasedStrategyReaderAccess(strategy_);\\r\\n\\r\\n (v.addr, , , ) = strategy.getDefaultState();\\r\\n\\r\\n v.tokens = new address[](2);\\r\\n v.tokens[0] = v.addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A];\\r\\n v.tokens[1] = v.addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B];\\r\\n\\r\\n v.converter = ITetuConverter(strategy.converter());\\r\\n\\r\\n v.priceOracle = AppLib._getPriceOracle(v.converter);\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(v.priceOracle, v.tokens, 2);\\r\\n\\r\\n (v.debtAmountB, v.collateralAmountA) = v.converter.getDebtAmountStored(strategy_, v.tokens[0], v.tokens[1], false);\\r\\n (v.debtAmountA, v.collateralAmountB) = v.converter.getDebtAmountStored(strategy_, v.tokens[1], v.tokens[0], false);\\r\\n\\r\\n // the app should have debt in one direction only - either direct or reverse\\r\\n // but dust debts in contrary direction are still possible\\r\\n if (v.debtAmountB > v.collateralAmountB) {\\r\\n if (v.debtAmountB > AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // there is direct debt\\r\\n requiredAmountToReduceDebt = getAmountToReduceDebt(\\r\\n strategy.totalAssets(),\\r\\n strategy.asset() == v.tokens[0],\\r\\n v.collateralAmountA,\\r\\n v.debtAmountB,\\r\\n [v.prices[0], v.prices[1]],\\r\\n [v.decs[0], v.decs[1]],\\r\\n requiredLockedAmountPercent\\r\\n );\\r\\n }\\r\\n } else {\\r\\n if (v.debtAmountA > AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // there is reverse debt\\r\\n requiredAmountToReduceDebt = getAmountToReduceDebt(\\r\\n strategy.totalAssets(),\\r\\n strategy.asset() == v.tokens[1],\\r\\n v.collateralAmountB,\\r\\n v.debtAmountA,\\r\\n [v.prices[1], v.prices[0]],\\r\\n [v.decs[1], v.decs[0]],\\r\\n requiredLockedAmountPercent\\r\\n );\\r\\n }\\r\\n }\\r\\n return requiredAmountToReduceDebt;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the amount by which the debt should be reduced to reduce locked-amount-percent below given value\\r\\n /// @param totalAssets Total assets of the strategy, in underlying\\r\\n /// @param isUnderlyingA True if A is underlying\\r\\n /// @param collateralAmountA Total collateral amount in asset A\\r\\n /// @param debtAmountB Total debt amount in asset B\\r\\n /// @param pricesAB Prices of A and B, decimals 18\\r\\n /// @param decsAB 10**decimals for A and B\\r\\n /// @param requiredLockedAmountPercent Required value of locked amount percent [0..100]\\r\\n /// @return deltaDebtAmountB The amount by which the debt should be reduced, asset B\\r\\n function getAmountToReduceDebt(\\r\\n uint totalAssets,\\r\\n bool isUnderlyingA,\\r\\n uint collateralAmountA,\\r\\n uint debtAmountB,\\r\\n uint[2] memory pricesAB,\\r\\n uint[2] memory decsAB,\\r\\n uint requiredLockedAmountPercent\\r\\n ) public pure returns (uint deltaDebtAmountB) {\\r\\n if (debtAmountB != 0 && totalAssets != 0) {\\r\\n uint alpha18 = 1e18 * collateralAmountA * decsAB[1] / decsAB[0] / debtAmountB;\\r\\n\\r\\n uint indexUnderlying = isUnderlyingA ? 0 : 1;\\r\\n uint lockedPercent18 = 1e18\\r\\n * AppLib.sub0(collateralAmountA * pricesAB[0] / decsAB[0], debtAmountB * pricesAB[1] / decsAB[1])\\r\\n / (totalAssets * pricesAB[indexUnderlying] / decsAB[indexUnderlying]);\\r\\n uint delta = AppLib.sub0(alpha18 * pricesAB[0] / 1e18, pricesAB[1]);\\r\\n\\r\\n deltaDebtAmountB = delta == 0\\r\\n ? 0 // weird case\\r\\n : AppLib.sub0(lockedPercent18, requiredLockedAmountPercent * 1e16)\\r\\n * totalAssets\\r\\n * pricesAB[indexUnderlying]\\r\\n / decsAB[indexUnderlying]\\r\\n / delta;\\r\\n }\\r\\n\\r\\n return deltaDebtAmountB * decsAB[1] / 1e18;\\r\\n }\\r\\n //endregion -------------------------------------------------- Calculate amount to reduce debt\\r\\n}\\r\\n\",\"keccak256\":\"0x6a02b56f946a2db1ffca47387ba6a06cf50d5f8693b5a08ee703c8fbb02cb0e2\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50611bb2806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c8063369e2efc1461006757806359af44dc146100945780635d698b52146100aa578063e8405269146100b2578063ebe4aef2146100c5578063fe03683f146100d8575b600080fd5b61007a610075366004611557565b6100eb565b604080519283526020830191909152015b60405180910390f35b61009c600181565b60405190815260200161008b565b61009c600281565b61009c6100c0366004611639565b6107d4565b61009c6100d33660046116a9565b6109c5565b61009c6100e63660046116a9565b61110f565b60008061014d60405180610140016040528060006001600160a01b031681526020016060815260200160608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008490506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610192573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ba9190810190611833565b50505090506000816000815181106101d4576101d4611941565b602002602001015190506000826001815181106101f3576101f3611941565b60200260200101519050836001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f9190611957565b6001600160a01b031685526040805160028082526060820183529091602083019080368337019050508560200181905250836001600160a01b0316633cd8045e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f29190611957565b6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611957565b856020015160008151811061036a5761036a611941565b6001600160a01b03909216602092830291909101820152850151805160009061039557610395611941565b60200260200101516001600160a01b0316826001600160a01b0316146103bb57816103bd565b805b85602001516001815181106103d4576103d4611941565b60200260200101906001600160a01b031690816001600160a01b0316815250506000610403866000015161123d565b90506104158187602001516002611302565b606088015260408701528551602087015180516001600160a01b039092169163e4c2be70918c9160009061044b5761044b611941565b6020026020010151896020015160018151811061046a5761046a611941565b602002602001015160016040518563ffffffff1660e01b81526004016104939493929190611974565b6040805180830381865afa1580156104af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d3919061199e565b60a088015260808701528551602087015180516001600160a01b039092169163e4c2be70918c91600190811061050b5761050b611941565b6020026020010151896020015160008151811061052a5761052a611941565b602002602001015160016040518563ffffffff1660e01b81526004016105539493929190611974565b6040805180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061199e565b60e088015260c0870152604086015180516000906105b3576105b3611941565b602002602001015186606001516001815181106105d2576105d2611941565b602002602001015187606001516000815181106105f1576105f1611941565b6020026020010151886040015160018151811061061057610610611941565b6020026020010151896080015161062791906119d8565b61063191906119d8565b61063b91906119ef565b61064591906119ef565b6101008701526040860151805160009061066157610661611941565b6020026020010151866060015160018151811061068057610680611941565b6020026020010151876060015160008151811061069f5761069f611941565b602002602001015188604001516001815181106106be576106be611941565b60200260200101518960e001516106d591906119d8565b6106df91906119d8565b6106e991906119ef565b6106f391906119ef565b61012087015260c086015161010087015161070e9190611a11565b8661012001518760a001516107239190611a11565b1161072f576000610763565b8560c001518661010001518761012001518860a0015161074f9190611a11565b6107599190611a24565b6107639190611a24565b856001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190611a37565b97509750505050505050915091565b600084158015906107e457508715155b15610996578251602084015160009187916108078a670de0b6b3a76400006119d8565b61081191906119d8565b61081b91906119ef565b61082591906119ef565b9050600088610835576001610838565b60005b60ff169050600085826002811061085157610851611941565b602002015187836002811061086857610868611941565b6020020151610877908d6119d8565b61088191906119ef565b865188516108c19190610894908d6119d8565b61089e91906119ef565b6020808a0151908b01516108b2908d6119d8565b6108bc91906119ef565b611501565b6108d390670de0b6b3a76400006119d8565b6108dd91906119ef565b90506000610912670de0b6b3a7640000898360200201516108fe90876119d8565b61090891906119ef565b60208a0151611501565b9050801561098c578087846002811061092d5761092d611941565b602002015189856002811061094457610944611941565b60200201518e61095f866108bc8c662386f26fc100006119d8565b61096991906119d8565b61097391906119d8565b61097d91906119ef565b61098791906119ef565b61098f565b60005b9450505050505b6020830151670de0b6b3a7640000906109af90836119d8565b6109b991906119ef565b98975050505050505050565b6000610a2f6040518061014001604052806060815260200160006001600160a01b0316815260200160608152602001606081526020016060815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6000849050806001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9a9190810190611833565b50505060808301526040805160028082526060820183529091602083019080368337505050825260808201518051600090610ad757610ad7611941565b60200260200101518260000151600081518110610af657610af6611941565b60200260200101906001600160a01b031690816001600160a01b0316815250508160800151600181518110610b2d57610b2d611941565b60200260200101518260000151600181518110610b4c57610b4c611941565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bce9190611957565b6001600160a01b031660208301819052610be79061123d565b6001600160a01b031660a083018190528251610c0591906002611302565b606084015260408301526020820151825180516001600160a01b039092169163e4c2be70918891600090610c3b57610c3b611941565b60200260200101518560000151600181518110610c5a57610c5a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610c839493929190611974565b6040805180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc3919061199e565b60e084015260c08301526020820151825180516001600160a01b039092169163e4c2be709188916001908110610cfb57610cfb611941565b60200260200101518560000151600081518110610d1a57610d1a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610d439493929190611974565b6040805180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d83919061199e565b610120840181905261010084019190915260c08301511115610f5b5760648260c001511115610f5657610f53816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ded573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e119190611a37565b83518051600090610e2457610e24611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190611957565b6001600160a01b0316148460e001518560c0015160405180604001604052808860400151600081518110610ecd57610ecd611941565b602002602001015181526020018860400151600181518110610ef157610ef1611941565b602002602001015181525060405180604001604052808960600151600081518110610f1e57610f1e611941565b602002602001015181526020018960600151600181518110610f4257610f42611941565b60200260200101518152508a6107d4565b92505b611106565b6064826101000151111561110657611103816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fce9190611a37565b835180516001908110610fe357610fe3611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110569190611957565b6001600160a01b0316148461012001518561010001516040518060400160405280886040015160018151811061108e5761108e611941565b6020026020010151815260200188604001516000815181106110b2576110b2611941565b6020026020010151815250604051806040016040528089606001516001815181106110df576110df611941565b602002602001015181526020018960600151600081518110610f4257610f42611941565b92505b50505b92915050565b6000808390506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261117d9190810190611833565b50925050506111b68160018151811061119857611198611941565b602002602001015160038111156111b1576111b1611a50565b611522565b156111ed57806003815181106111ce576111ce611941565b60200260200101516000036111e857600192505050611109565b611232565b6000806111f9876100eb565b909250905060008161120c8460646119d8565b61121691906119ef565b90508681111561122e57600295505050505050611109565b5050505b506000949350505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a19190611957565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190611957565b6060808267ffffffffffffffff81111561131e5761131e611582565b604051908082528060200260200182016040528015611347578160200160208202803683370190505b5091508267ffffffffffffffff81111561136357611363611582565b60405190808252806020026020018201604052801561138c578160200160208202803683370190505b50905060005b838110156114f8578481815181106113ac576113ac611941565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190611a66565b61142090600a611b6d565b82828151811061143257611432611941565b602002602001018181525050856001600160a01b031663b3596f0786838151811061145f5761145f611941565b60200260200101516040518263ffffffff1660e01b815260040161149291906001600160a01b0391909116815260200190565b602060405180830381865afa1580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190611a37565b8382815181106114e5576114e5611941565b6020908102919091010152600101611392565b50935093915050565b600081831161151157600061151b565b61151b8284611a24565b9392505050565b6000600182600381111561153857611538611a50565b1192915050565b6001600160a01b038116811461155457600080fd5b50565b60006020828403121561156957600080fd5b813561151b8161153f565b801515811461155457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c1576115c1611582565b604052919050565b600082601f8301126115da57600080fd5b6040516040810181811067ffffffffffffffff821117156115fd576115fd611582565b806040525080604084018581111561161457600080fd5b845b8181101561162e578035835260209283019201611616565b509195945050505050565b6000806000806000806000610120888a03121561165557600080fd5b87359650602088013561166781611574565b955060408801359450606088013593506116848960808a016115c9565b92506116938960c08a016115c9565b9150610100880135905092959891949750929550565b600080604083850312156116bc57600080fd5b82356116c78161153f565b946020939093013593505050565b600067ffffffffffffffff8211156116ef576116ef611582565b5060051b60200190565b600082601f83011261170a57600080fd5b8151602061171f61171a836116d5565b611598565b82815260059290921b8401810191818101908684111561173e57600080fd5b8286015b848110156117695780518060020b811461175c5760008081fd5b8352918301918301611742565b509695505050505050565b600082601f83011261178557600080fd5b8151602061179561171a836116d5565b82815260059290921b840181019181810190868411156117b457600080fd5b8286015b8481101561176957805183529183019183016117b8565b600082601f8301126117e057600080fd5b815160206117f061171a836116d5565b82815260059290921b8401810191818101908684111561180f57600080fd5b8286015b8481101561176957805161182681611574565b8352918301918301611813565b6000806000806080858703121561184957600080fd5b845167ffffffffffffffff8082111561186157600080fd5b818701915087601f83011261187557600080fd5b8151602061188561171a836116d5565b82815260059290921b8401810191818101908b8411156118a457600080fd5b948201945b838610156118cb5785516118bc8161153f565b825294820194908201906118a9565b918a01519198509093505050808211156118e457600080fd5b6118f0888389016116f9565b9450604087015191508082111561190657600080fd5b61191288838901611774565b9350606087015191508082111561192857600080fd5b50611935878288016117cf565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561196957600080fd5b815161151b8161153f565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b600080604083850312156119b157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611109576111096119c2565b600082611a0c57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611109576111096119c2565b81810381811115611109576111096119c2565b600060208284031215611a4957600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215611a7857600080fd5b815160ff8116811461151b57600080fd5b600181815b80851115611ac4578160001904821115611aaa57611aaa6119c2565b80851615611ab757918102915b93841c9390800290611a8e565b509250929050565b600082611adb57506001611109565b81611ae857506000611109565b8160018114611afe5760028114611b0857611b24565b6001915050611109565b60ff841115611b1957611b196119c2565b50506001821b611109565b5060208310610133831016604e8410600b8410161715611b47575081810a611109565b611b518383611a89565b8060001904821115611b6557611b656119c2565b029392505050565b600061151b60ff841683611acc56fea26469706673582212206270f813eb6756096ed4e7294da6a02c20b8f68de5b4095205abe97a8ca24ba664736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063369e2efc1461006757806359af44dc146100945780635d698b52146100aa578063e8405269146100b2578063ebe4aef2146100c5578063fe03683f146100d8575b600080fd5b61007a610075366004611557565b6100eb565b604080519283526020830191909152015b60405180910390f35b61009c600181565b60405190815260200161008b565b61009c600281565b61009c6100c0366004611639565b6107d4565b61009c6100d33660046116a9565b6109c5565b61009c6100e63660046116a9565b61110f565b60008061014d60405180610140016040528060006001600160a01b031681526020016060815260200160608152602001606081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008490506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610192573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ba9190810190611833565b50505090506000816000815181106101d4576101d4611941565b602002602001015190506000826001815181106101f3576101f3611941565b60200260200101519050836001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561023b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025f9190611957565b6001600160a01b031685526040805160028082526060820183529091602083019080368337019050508560200181905250836001600160a01b0316633cd8045e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f29190611957565b6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561032f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103539190611957565b856020015160008151811061036a5761036a611941565b6001600160a01b03909216602092830291909101820152850151805160009061039557610395611941565b60200260200101516001600160a01b0316826001600160a01b0316146103bb57816103bd565b805b85602001516001815181106103d4576103d4611941565b60200260200101906001600160a01b031690816001600160a01b0316815250506000610403866000015161123d565b90506104158187602001516002611302565b606088015260408701528551602087015180516001600160a01b039092169163e4c2be70918c9160009061044b5761044b611941565b6020026020010151896020015160018151811061046a5761046a611941565b602002602001015160016040518563ffffffff1660e01b81526004016104939493929190611974565b6040805180830381865afa1580156104af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104d3919061199e565b60a088015260808701528551602087015180516001600160a01b039092169163e4c2be70918c91600190811061050b5761050b611941565b6020026020010151896020015160008151811061052a5761052a611941565b602002602001015160016040518563ffffffff1660e01b81526004016105539493929190611974565b6040805180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061199e565b60e088015260c0870152604086015180516000906105b3576105b3611941565b602002602001015186606001516001815181106105d2576105d2611941565b602002602001015187606001516000815181106105f1576105f1611941565b6020026020010151886040015160018151811061061057610610611941565b6020026020010151896080015161062791906119d8565b61063191906119d8565b61063b91906119ef565b61064591906119ef565b6101008701526040860151805160009061066157610661611941565b6020026020010151866060015160018151811061068057610680611941565b6020026020010151876060015160008151811061069f5761069f611941565b602002602001015188604001516001815181106106be576106be611941565b60200260200101518960e001516106d591906119d8565b6106df91906119d8565b6106e991906119ef565b6106f391906119ef565b61012087015260c086015161010087015161070e9190611a11565b8661012001518760a001516107239190611a11565b1161072f576000610763565b8560c001518661010001518761012001518860a0015161074f9190611a11565b6107599190611a24565b6107639190611a24565b856001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c59190611a37565b97509750505050505050915091565b600084158015906107e457508715155b15610996578251602084015160009187916108078a670de0b6b3a76400006119d8565b61081191906119d8565b61081b91906119ef565b61082591906119ef565b9050600088610835576001610838565b60005b60ff169050600085826002811061085157610851611941565b602002015187836002811061086857610868611941565b6020020151610877908d6119d8565b61088191906119ef565b865188516108c19190610894908d6119d8565b61089e91906119ef565b6020808a0151908b01516108b2908d6119d8565b6108bc91906119ef565b611501565b6108d390670de0b6b3a76400006119d8565b6108dd91906119ef565b90506000610912670de0b6b3a7640000898360200201516108fe90876119d8565b61090891906119ef565b60208a0151611501565b9050801561098c578087846002811061092d5761092d611941565b602002015189856002811061094457610944611941565b60200201518e61095f866108bc8c662386f26fc100006119d8565b61096991906119d8565b61097391906119d8565b61097d91906119ef565b61098791906119ef565b61098f565b60005b9450505050505b6020830151670de0b6b3a7640000906109af90836119d8565b6109b991906119ef565b98975050505050505050565b6000610a2f6040518061014001604052806060815260200160006001600160a01b0316815260200160608152602001606081526020016060815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b6000849050806001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a9a9190810190611833565b50505060808301526040805160028082526060820183529091602083019080368337505050825260808201518051600090610ad757610ad7611941565b60200260200101518260000151600081518110610af657610af6611941565b60200260200101906001600160a01b031690816001600160a01b0316815250508160800151600181518110610b2d57610b2d611941565b60200260200101518260000151600181518110610b4c57610b4c611941565b60200260200101906001600160a01b031690816001600160a01b031681525050806001600160a01b031663bd38837b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610baa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bce9190611957565b6001600160a01b031660208301819052610be79061123d565b6001600160a01b031660a083018190528251610c0591906002611302565b606084015260408301526020820151825180516001600160a01b039092169163e4c2be70918891600090610c3b57610c3b611941565b60200260200101518560000151600181518110610c5a57610c5a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610c839493929190611974565b6040805180830381865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc3919061199e565b60e084015260c08301526020820151825180516001600160a01b039092169163e4c2be709188916001908110610cfb57610cfb611941565b60200260200101518560000151600081518110610d1a57610d1a611941565b602002602001015160006040518563ffffffff1660e01b8152600401610d439493929190611974565b6040805180830381865afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d83919061199e565b610120840181905261010084019190915260c08301511115610f5b5760648260c001511115610f5657610f53816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ded573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e119190611a37565b83518051600090610e2457610e24611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190611957565b6001600160a01b0316148460e001518560c0015160405180604001604052808860400151600081518110610ecd57610ecd611941565b602002602001015181526020018860400151600181518110610ef157610ef1611941565b602002602001015181525060405180604001604052808960600151600081518110610f1e57610f1e611941565b602002602001015181526020018960600151600181518110610f4257610f42611941565b60200260200101518152508a6107d4565b92505b611106565b6064826101000151111561110657611103816001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fce9190611a37565b835180516001908110610fe357610fe3611941565b60200260200101516001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110569190611957565b6001600160a01b0316148461012001518561010001516040518060400160405280886040015160018151811061108e5761108e611941565b6020026020010151815260200188604001516000815181106110b2576110b2611941565b6020026020010151815250604051806040016040528089606001516001815181106110df576110df611941565b602002602001015181526020018960600151600081518110610f4257610f42611941565b92505b50505b92915050565b6000808390506000816001600160a01b0316635412335d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611155573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261117d9190810190611833565b50925050506111b68160018151811061119857611198611941565b602002602001015160038111156111b1576111b1611a50565b611522565b156111ed57806003815181106111ce576111ce611941565b60200260200101516000036111e857600192505050611109565b611232565b6000806111f9876100eb565b909250905060008161120c8460646119d8565b61121691906119ef565b90508681111561122e57600295505050505050611109565b5050505b506000949350505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa15801561127d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a19190611957565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111099190611957565b6060808267ffffffffffffffff81111561131e5761131e611582565b604051908082528060200260200182016040528015611347578160200160208202803683370190505b5091508267ffffffffffffffff81111561136357611363611582565b60405190808252806020026020018201604052801561138c578160200160208202803683370190505b50905060005b838110156114f8578481815181106113ac576113ac611941565b60200260200101516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190611a66565b61142090600a611b6d565b82828151811061143257611432611941565b602002602001018181525050856001600160a01b031663b3596f0786838151811061145f5761145f611941565b60200260200101516040518263ffffffff1660e01b815260040161149291906001600160a01b0391909116815260200190565b602060405180830381865afa1580156114af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114d39190611a37565b8382815181106114e5576114e5611941565b6020908102919091010152600101611392565b50935093915050565b600081831161151157600061151b565b61151b8284611a24565b9392505050565b6000600182600381111561153857611538611a50565b1192915050565b6001600160a01b038116811461155457600080fd5b50565b60006020828403121561156957600080fd5b813561151b8161153f565b801515811461155457600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156115c1576115c1611582565b604052919050565b600082601f8301126115da57600080fd5b6040516040810181811067ffffffffffffffff821117156115fd576115fd611582565b806040525080604084018581111561161457600080fd5b845b8181101561162e578035835260209283019201611616565b509195945050505050565b6000806000806000806000610120888a03121561165557600080fd5b87359650602088013561166781611574565b955060408801359450606088013593506116848960808a016115c9565b92506116938960c08a016115c9565b9150610100880135905092959891949750929550565b600080604083850312156116bc57600080fd5b82356116c78161153f565b946020939093013593505050565b600067ffffffffffffffff8211156116ef576116ef611582565b5060051b60200190565b600082601f83011261170a57600080fd5b8151602061171f61171a836116d5565b611598565b82815260059290921b8401810191818101908684111561173e57600080fd5b8286015b848110156117695780518060020b811461175c5760008081fd5b8352918301918301611742565b509695505050505050565b600082601f83011261178557600080fd5b8151602061179561171a836116d5565b82815260059290921b840181019181810190868411156117b457600080fd5b8286015b8481101561176957805183529183019183016117b8565b600082601f8301126117e057600080fd5b815160206117f061171a836116d5565b82815260059290921b8401810191818101908684111561180f57600080fd5b8286015b8481101561176957805161182681611574565b8352918301918301611813565b6000806000806080858703121561184957600080fd5b845167ffffffffffffffff8082111561186157600080fd5b818701915087601f83011261187557600080fd5b8151602061188561171a836116d5565b82815260059290921b8401810191818101908b8411156118a457600080fd5b948201945b838610156118cb5785516118bc8161153f565b825294820194908201906118a9565b918a01519198509093505050808211156118e457600080fd5b6118f0888389016116f9565b9450604087015191508082111561190657600080fd5b61191288838901611774565b9350606087015191508082111561192857600080fd5b50611935878288016117cf565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561196957600080fd5b815161151b8161153f565b6001600160a01b039485168152928416602084015292166040820152901515606082015260800190565b600080604083850312156119b157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417611109576111096119c2565b600082611a0c57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115611109576111096119c2565b81810381811115611109576111096119c2565b600060208284031215611a4957600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215611a7857600080fd5b815160ff8116811461151b57600080fd5b600181815b80851115611ac4578160001904821115611aaa57611aaa6119c2565b80851615611ab757918102915b93841c9390800290611a8e565b509250929050565b600082611adb57506001611109565b81611ae857506000611109565b8160018114611afe5760028114611b0857611b24565b6001915050611109565b60ff841115611b1957611b196119c2565b50506001821b611109565b5060208310610133831016604e8410600b8410161715611b47575081810a611109565b611b518383611a89565b8060001904821115611b6557611b656119c2565b029392505050565b600061151b60ff841683611acc56fea26469706673582212206270f813eb6756096ed4e7294da6a02c20b8f68de5b4095205abe97a8ca24ba664736f6c63430008110033", "devdoc": { "kind": "dev", "methods": { diff --git a/deployments/matic/UniswapV3ConverterStrategy.json b/deployments/matic/UniswapV3ConverterStrategy.json index 38d1fc6f..f1381a98 100644 --- a/deployments/matic/UniswapV3ConverterStrategy.json +++ b/deployments/matic/UniswapV3ConverterStrategy.json @@ -1,5 +1,5 @@ { - "address": "0x70aFf33907e31269DdA0e6F1a7b0415AAE288101", + "address": "0xA946047640B6e0c098085B19e781D9706faF5f13", "abi": [ { "anonymous": false, @@ -1118,63 +1118,63 @@ "type": "function" } ], - "transactionHash": "0xa13e7dd3a796acd60864b10d3bc04545e3e051fc333bb37450870b66f1c4b411", + "transactionHash": "0xa7625e2ae4d36e612a425e83fc54500205f7d035b6c83ed812ebde9c7924b5e9", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0x70aFf33907e31269DdA0e6F1a7b0415AAE288101", - "transactionIndex": 115, - "gasUsed": "5184530", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000008000000000000000000004000080000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000080000000000000000000200080000000000000000000000400000000000000000000000000000000004000000000000080000001000000040000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0xdb9fbdb85409257d1b260c55f1332da9dae5e89b8de5630ebaf60731e3127cab", - "transactionHash": "0xa13e7dd3a796acd60864b10d3bc04545e3e051fc333bb37450870b66f1c4b411", + "contractAddress": "0xA946047640B6e0c098085B19e781D9706faF5f13", + "transactionIndex": 196, + "gasUsed": "5163112", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000000001000000000000800000000000400000000100000000000000000000000000040000000000000000000000000004000080000000004000000000000000000000000001000000000000000000000080000000000000000000200000000000000000000000000400000000000000000000000000000000004000000000000000000001000000040000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0x0e9d225b415aa1e180f5bc6b4a888b9a19aab4f6132209bf55cb703b4f91f372", + "transactionHash": "0xa7625e2ae4d36e612a425e83fc54500205f7d035b6c83ed812ebde9c7924b5e9", "logs": [ { - "transactionIndex": 115, - "blockNumber": 54803724, - "transactionHash": "0xa13e7dd3a796acd60864b10d3bc04545e3e051fc333bb37450870b66f1c4b411", - "address": "0x70aFf33907e31269DdA0e6F1a7b0415AAE288101", + "transactionIndex": 196, + "blockNumber": 55572515, + "transactionHash": "0xa7625e2ae4d36e612a425e83fc54500205f7d035b6c83ed812ebde9c7924b5e9", + "address": "0xA946047640B6e0c098085B19e781D9706faF5f13", "topics": [ "0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498" ], "data": "0x00000000000000000000000000000000000000000000000000000000000000ff", - "logIndex": 656, - "blockHash": "0xdb9fbdb85409257d1b260c55f1332da9dae5e89b8de5630ebaf60731e3127cab" + "logIndex": 975, + "blockHash": "0x0e9d225b415aa1e180f5bc6b4a888b9a19aab4f6132209bf55cb703b4f91f372" }, { - "transactionIndex": 115, - "blockNumber": 54803724, - "transactionHash": "0xa13e7dd3a796acd60864b10d3bc04545e3e051fc333bb37450870b66f1c4b411", + "transactionIndex": 196, + "blockNumber": 55572515, + "transactionHash": "0xa7625e2ae4d36e612a425e83fc54500205f7d035b6c83ed812ebde9c7924b5e9", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x0000000000000000000000007c7379531b2aee82e4ca06d4175d13b9cbeafd49" ], - "data": "0x000000000000000000000000000000000000000000000000001ba0f42f774e0000000000000000000000000000000000000000000000000262c96991a0afcd5a0000000000000000000000000000000000000000000024377d7376565f13b4f700000000000000000000000000000000000000000000000262adc89d71387f5a0000000000000000000000000000000000000000000024377d8f174a8e8b02f7", - "logIndex": 657, - "blockHash": "0xdb9fbdb85409257d1b260c55f1332da9dae5e89b8de5630ebaf60731e3127cab" + "data": "0x00000000000000000000000000000000000000000000000000eb4a91aed81560000000000000000000000000000000000000000000000001ccb116e7cb47e15300000000000000000000000000000000000000000002e458fa5b2ef1e5c2fe1d000000000000000000000000000000000000000000000001cbc5cc561c6fcbf300000000000000000000000000000000000000000002e458fb467983949b137d", + "logIndex": 976, + "blockHash": "0x0e9d225b415aa1e180f5bc6b4a888b9a19aab4f6132209bf55cb703b4f91f372" } ], - "blockNumber": 54803724, - "cumulativeGasUsed": "26953952", + "blockNumber": 55572515, + "cumulativeGasUsed": "26002352", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 36, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"block\",\"type\":\"uint256\"}],\"name\":\"ContractInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"withdrawnAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorEmergencyExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"consumedAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorEnter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"liquidityAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"withdrawnAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"investedAssetsNewPrices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedByPrices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedHandleRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lostHandleRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lostDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paidDebtToInsurance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountPerf\",\"type\":\"uint256\"}],\"name\":\"OnHardWorkEarnedLost\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldLogic\",\"type\":\"address\"}],\"name\":\"RevisionIncreased\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CONTROLLABLE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CONVERTER_STRATEGY_BASE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PLATFORM\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"STRATEGY_BASE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"STRATEGY_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNISWAPV3_DEPOSITOR_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"calcInvestedAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"investedAssetsOut\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capacity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"compoundRatio\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"converter\",\"outputs\":[{\"internalType\":\"contract ITetuConverter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"created\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createdBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"debtToInsurance\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doHardWork\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"earned\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emergencyExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDefaultState\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"addr\",\"type\":\"address[]\"},{\"internalType\":\"int24[]\",\"name\":\"tickData\",\"type\":\"int24[]\"},{\"internalType\":\"uint256[]\",\"name\":\"nums\",\"type\":\"uint256[]\"},{\"internalType\":\"bool[]\",\"name\":\"boolValues\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"fee0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fee1\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPropNotUnderlying18\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"slot\",\"type\":\"uint256\"}],\"name\":\"getSlot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSpecificState\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"nums\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oldLogic\",\"type\":\"address\"}],\"name\":\"increaseRevision\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"controller_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"splitter_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"converter_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool_\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickRange_\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"rebalanceTickRange_\",\"type\":\"int24\"},{\"internalType\":\"uint256[4]\",\"name\":\"fuseThresholds\",\"type\":\"uint256[4]\"}],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"updateTotalAssetsBeforeInvest_\",\"type\":\"bool\"}],\"name\":\"investAll\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"investedAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_value\",\"type\":\"address\"}],\"name\":\"isController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_value\",\"type\":\"address\"}],\"name\":\"isGovernance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isReadyToHardWork\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"liquidationThresholds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"needRebalance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"assets_\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts_\",\"type\":\"uint256[]\"}],\"name\":\"onTransferAmounts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceFeeRatio\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceReceiver\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"planEntryData\",\"type\":\"bytes\"}],\"name\":\"quoteWithdrawByAgg\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"tokenToSwap\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amountToSwap\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"checkNeedRebalance\",\"type\":\"bool\"}],\"name\":\"rebalanceNoSwaps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reinvestThresholdPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"theAsset_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"}],\"name\":\"requirePayAmountBack\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revision\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setCompoundRatio\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"}],\"name\":\"setFuseStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"values\",\"type\":\"uint256[4]\"}],\"name\":\"setFuseThresholds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"setLiquidationThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"percent_\",\"type\":\"uint256\"}],\"name\":\"setReinvestThresholdPercent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyProfitHolder\",\"type\":\"address\"}],\"name\":\"setStrategyProfitHolder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setStrategySpecificName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"done\",\"type\":\"uint256\"}],\"name\":\"setWithdrawDone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fee_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"ratio_\",\"type\":\"uint256\"}],\"name\":\"setupPerformanceFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategySpecificName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0Owed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Owed\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"uniswapV3MintCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllToSplitter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenToSwap_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"aggregator_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amountToSwap_\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"planEntryData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"entryToPool\",\"type\":\"uint256\"}],\"name\":\"withdrawByAggStep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"completed\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawToSplitter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"a17\",\"kind\":\"dev\",\"methods\":{\"claim()\":{\"details\":\"Manual claim rewards.\"},\"created()\":{\"returns\":{\"_0\":\"Creation timestamp\"}},\"createdBlock()\":{\"returns\":{\"_0\":\"Creation block number\"}},\"doHardWork()\":{\"returns\":{\"earned\":\"Earned amount in terms of {asset}\",\"lost\":\"Lost amount in terms of {asset}\"}},\"emergencyExit()\":{\"details\":\"In case of any issue operator can withdraw all from pool.\"},\"getDefaultState()\":{\"returns\":{\"addr\":\"[tokenA, tokenB, pool, profitHolder]\",\"boolValues\":\"[isStablePool, depositorSwapTokens]\",\"nums\":\"[totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"getFees()\":{\"returns\":{\"fee0\":\"and fee1.\"}},\"getPropNotUnderlying18()\":{\"returns\":{\"_0\":\"Proportion of the not-underlying [0...1e18]\"}},\"getSlot(uint256)\":{\"details\":\"Gets a slot as bytes32\"},\"getSpecificState()\":{\"returns\":{\"nums\":\"Balances of [tokenA, tokenB] for profit holder\"}},\"increaseRevision(address)\":{\"details\":\"Revision should be increased on each contract upgrade\"},\"init(address,address,address,address,int24,int24,uint256[4])\":{\"params\":{\"controller_\":\"The address of the controller.\",\"converter_\":\"The address of the converter.\",\"fuseThresholds\":\"Price thresholds for tokens [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\",\"pool_\":\"The address of the pool.\",\"rebalanceTickRange_\":\"The tick range for rebalancing.\",\"splitter_\":\"The address of the splitter.\",\"tickRange_\":\"The tick range for the liquidity position.\"}},\"investAll(uint256,bool)\":{\"params\":{\"updateTotalAssetsBeforeInvest_\":\"Recalculate total assets amount before depositing. It can be false if we know exactly, that the amount is already actual.\"},\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}},\"isController(address)\":{\"details\":\"Return true if given address is controller\"},\"isReadyToHardWork()\":{\"returns\":{\"_0\":\"A boolean indicating if the strategy is ready for hard work.\"}},\"needRebalance()\":{\"returns\":{\"_0\":\"A boolean indicating if {rebalanceNoSwaps} should be called.\"}},\"onTransferAmounts(address[],uint256[])\":{\"params\":{\"amounts_\":\"Amount of {asset_} that has been sent to the user's balance\",\"assets_\":\"Any asset sent to the balance, i.e. inside repayTheBorrow\"}},\"performanceFee()\":{\"details\":\"use FEE_DENOMINATOR\"},\"previousImplementation()\":{\"details\":\"Previous logic implementation\"},\"rebalanceNoSwaps(bool)\":{\"params\":{\"checkNeedRebalance\":\"Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\"}},\"requirePayAmountBack(address,uint256)\":{\"params\":{\"amount_\":\"Required amount of {theAsset_}\",\"theAsset_\":\"Required asset (either collateral or borrow), it can be NOT underlying\"},\"returns\":{\"amountOut\":\"Amount that was send OR can be claimed on the next call. The caller should control own balance to know if the amount was actually send (because we need compatibility with exist not-NSR strategies)\"}},\"revision()\":{\"details\":\"Contract upgrade counter\"},\"setCompoundRatio(uint256)\":{\"details\":\"PlatformVoter can change compound ratio for some strategies. A strategy can implement another logic for some uniq cases.\"},\"setFuseStatus(uint256)\":{\"params\":{\"status\":\"See PairBasedStrategyLib.FuseStatus enum for possible values\"}},\"setFuseThresholds(uint256[4])\":{\"params\":{\"values\":\"Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\"}},\"setLiquidationThreshold(address,uint256)\":{\"details\":\"Liquidation thresholds are used to detect dust in many cases, not only in liquidation case\",\"params\":{\"amount\":\"Min amount of token allowed to liquidate, token's decimals are used.\"}},\"setReinvestThresholdPercent(uint256)\":{\"params\":{\"percent_\":\"New value of the percent, decimals = {REINVEST_THRESHOLD_PERCENT_DENOMINATOR}\"}},\"setStrategyProfitHolder(address)\":{\"details\":\"Set a dedicated contract for rewards for properly counting. It is safe to allow change it to operator - we suppose the contract only temporally store the last rewards.\"},\"setStrategySpecificName(string)\":{\"details\":\"The name will be used for UI.\"},\"setWithdrawDone(uint256)\":{\"params\":{\"done\":\"0 - full withdraw required, 1 - full withdraw was done\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"totalAssets()\":{\"details\":\"Total amount of underlying assets under control of this strategy.\"},\"uniswapV3MintCallback(uint256,uint256,bytes)\":{\"params\":{\"amount0Owed\":\"The amount of token0 owed to the pool.\",\"amount1Owed\":\"The amount of token1 owed to the pool.\"}},\"withdrawAllToSplitter()\":{\"details\":\"Withdraws all underlying assets to the vault\",\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}},\"withdrawByAggStep(address,address,uint256,bytes,bytes,uint256)\":{\"details\":\"All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\",\"params\":{\"aggregator_\":\"Aggregator that should be used on next swap. 0 - use liquidator\",\"amountToSwap_\":\"Amount that should be swapped. 0 - no swap\",\"entryToPool\":\"Allow to enter to the pool at the end. Use false if you are going to make several iterations. It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment 0 - not allowed, 1 - allowed, 2 - allowed only if completed\",\"planEntryData\":\"PLAN_XXX + additional data, see IterationPlanKinds\",\"swapData\":\"Swap rote that was prepared off-chain.\",\"tokenToSwap_\":\"What token should be swapped to other\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to the required proportions.\"}},\"withdrawToSplitter(uint256)\":{\"details\":\"Withdraws some assets to the splitter\",\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}}},\"title\":\"Delta-neutral liquidity hedging converter fill-up/swap rebalancing strategy for UniswapV3\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CONTROLLABLE_VERSION()\":{\"notice\":\"Version of the contract\"},\"capacity()\":{\"notice\":\"Unlimited capacity by default\"},\"controller()\":{\"notice\":\"Return controller address saved in the contract slot\"},\"created()\":{\"notice\":\"Return creation timestamp\"},\"createdBlock()\":{\"notice\":\"Return creation block number\"},\"doHardWork()\":{\"notice\":\"Do hard work with reinvesting\"},\"getDefaultState()\":{\"notice\":\"Returns the current state of the contract\"},\"getFees()\":{\"notice\":\"Returns the fees for the current state.\"},\"getPropNotUnderlying18()\":{\"notice\":\"Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\"},\"init(address,address,address,address,int24,int24,uint256[4])\":{\"notice\":\"Initialize the strategy with the given parameters.\"},\"investAll(uint256,bool)\":{\"notice\":\"Stakes everything the strategy holds into the reward pool. amount_ Amount transferred to the strategy balance just before calling this function\"},\"investedAssets()\":{\"notice\":\"Amount of underlying assets converted to pool assets and invested to the pool.\"},\"isGovernance(address)\":{\"notice\":\"Return true if given address is setup as governance in Controller\"},\"isReadyToHardWork()\":{\"notice\":\"Check if the strategy is ready for hard work.\"},\"liquidationThresholds(address)\":{\"notice\":\"Minimum token amounts that can be liquidated\"},\"needRebalance()\":{\"notice\":\"Check if the strategy needs rebalancing.\"},\"onTransferAmounts(address[],uint256[])\":{\"notice\":\"TetuConverter calls this function when it sends any amount to user's balance\"},\"performanceFee()\":{\"notice\":\"A percent of total profit that is sent to the {performanceReceiver} before compounding\"},\"performanceReceiver()\":{\"notice\":\"{performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\"},\"quoteWithdrawByAgg(bytes)\":{\"notice\":\"Get info about a swap required by next call of {withdrawByAggStep} within the given plan\"},\"rebalanceNoSwaps(bool)\":{\"notice\":\"Rebalance using borrow/repay only, no swaps\"},\"requirePayAmountBack(address,uint256)\":{\"notice\":\"Converters asks to send some amount back. The results depend on whether the required amount is on the balance: 1. The {amount_} exists on the balance: send the amount to TetuConverter, return {amount_} 2. The {amount_} doesn't exist on the balance. Try to receive the {amount_}. 2.1. if the required amount is received: return {amount_} 2.2. if less amount X (X < {amount_}) is received return X - gap In the case 2 no amount is send to TetuConverter. Converter should make second call of requirePayAmountBack({amountOut}) to receive the assets.\"},\"setFuseStatus(uint256)\":{\"notice\":\"Manually set status of the fuse\"},\"setFuseThresholds(uint256[4])\":{\"notice\":\"Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF] Decimals 18. The thresholds are compared with prices from TetuConverter's price oracle. Example: [0.9, 0.92, 1.08, 1.1] Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF. Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\"},\"setWithdrawDone(uint256)\":{\"notice\":\"Set withdrawDone value. When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying. After completion of the conversion withdrawDone can be set to 1. So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\"},\"setupPerformanceFee(uint256,address,uint256)\":{\"notice\":\"Set performance fee, receiver and ratio\"},\"uniswapV3MintCallback(uint256,uint256,bytes)\":{\"notice\":\"Callback function called by Uniswap V3 pool on mint operation.\"},\"withdrawByAggStep(address,address,uint256,bytes,bytes,uint256)\":{\"notice\":\"Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool] Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt. You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\"}},\"notice\":\"This strategy provides delta-neutral liquidity hedging for Uniswap V3 pools. It rebalances the liquidity by utilizing fill-up and swap methods depending on the range size of the liquidity provided.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol\":\"UniswapV3ConverterStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xaeca7db2074d7c66a20c609539e1f1656e67f6981bf01f83ad6aa8aa140c8d2e\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/InterfaceIds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n/// @title Library for interface IDs\\n/// @author bogdoslav\\nlibrary InterfaceIds {\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant INTERFACE_IDS_LIB_VERSION = \\\"1.0.1\\\";\\n\\n /// default notation:\\n /// bytes4 public constant I_VOTER = type(IVoter).interfaceId;\\n\\n /// As type({Interface}).interfaceId can be changed,\\n /// when some functions changed at the interface,\\n /// so used hardcoded interface identifiers\\n\\n bytes4 public constant I_VOTER = bytes4(keccak256(\\\"IVoter\\\"));\\n bytes4 public constant I_BRIBE = bytes4(keccak256(\\\"IBribe\\\"));\\n bytes4 public constant I_GAUGE = bytes4(keccak256(\\\"IGauge\\\"));\\n bytes4 public constant I_VE_TETU = bytes4(keccak256(\\\"IVeTetu\\\"));\\n bytes4 public constant I_SPLITTER = bytes4(keccak256(\\\"ISplitter\\\"));\\n bytes4 public constant I_FORWARDER = bytes4(keccak256(\\\"IForwarder\\\"));\\n bytes4 public constant I_MULTI_POOL = bytes4(keccak256(\\\"IMultiPool\\\"));\\n bytes4 public constant I_CONTROLLER = bytes4(keccak256(\\\"IController\\\"));\\n bytes4 public constant I_TETU_ERC165 = bytes4(keccak256(\\\"ITetuERC165\\\"));\\n bytes4 public constant I_STRATEGY_V2 = bytes4(keccak256(\\\"IStrategyV2\\\"));\\n bytes4 public constant I_STRATEGY_V3 = bytes4(keccak256(\\\"IStrategyV3\\\"));\\n bytes4 public constant I_CONTROLLABLE = bytes4(keccak256(\\\"IControllable\\\"));\\n bytes4 public constant I_TETU_VAULT_V2 = bytes4(keccak256(\\\"ITetuVaultV2\\\"));\\n bytes4 public constant I_PLATFORM_VOTER = bytes4(keccak256(\\\"IPlatformVoter\\\"));\\n bytes4 public constant I_VE_DISTRIBUTOR = bytes4(keccak256(\\\"IVeDistributor\\\"));\\n bytes4 public constant I_TETU_CONVERTER = bytes4(keccak256(\\\"ITetuConverter\\\"));\\n bytes4 public constant I_VAULT_INSURANCE = bytes4(keccak256(\\\"IVaultInsurance\\\"));\\n bytes4 public constant I_STRATEGY_STRICT = bytes4(keccak256(\\\"IStrategyStrict\\\"));\\n bytes4 public constant I_ERC4626 = bytes4(keccak256(\\\"IERC4626\\\"));\\n\\n}\\n\",\"keccak256\":\"0x0b03305fffdb0ae7bca319c38ac0b43116765987cf61f529f156f46171e73de1\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/SlotsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n/// @title Library for setting / getting slot variables (used in upgradable proxy contracts)\\n/// @author bogdoslav\\nlibrary SlotsLib {\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant SLOT_LIB_VERSION = \\\"1.0.0\\\";\\n\\n // ************* GETTERS *******************\\n\\n /// @dev Gets a slot as bytes32\\n function getBytes32(bytes32 slot) internal view returns (bytes32 result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot as an address\\n function getAddress(bytes32 slot) internal view returns (address result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot as uint256\\n function getUint(bytes32 slot) internal view returns (uint result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n // ************* ARRAY GETTERS *******************\\n\\n /// @dev Gets an array length\\n function arrayLength(bytes32 slot) internal view returns (uint result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot array by index as address\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function addressAt(bytes32 slot, uint index) internal view returns (address result) {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n result := sload(pointer)\\n }\\n }\\n\\n /// @dev Gets a slot array by index as uint\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function uintAt(bytes32 slot, uint index) internal view returns (uint result) {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n result := sload(pointer)\\n }\\n }\\n\\n // ************* SETTERS *******************\\n\\n /// @dev Sets a slot with bytes32\\n /// @notice Check address for 0 at the setter\\n function set(bytes32 slot, bytes32 value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n /// @dev Sets a slot with address\\n /// @notice Check address for 0 at the setter\\n function set(bytes32 slot, address value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n /// @dev Sets a slot with uint\\n function set(bytes32 slot, uint value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n // ************* ARRAY SETTERS *******************\\n\\n /// @dev Sets a slot array at index with address\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function setAt(bytes32 slot, uint index, address value) internal {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n sstore(pointer, value)\\n }\\n }\\n\\n /// @dev Sets a slot array at index with uint\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function setAt(bytes32 slot, uint index, uint value) internal {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n sstore(pointer, value)\\n }\\n }\\n\\n /// @dev Sets an array length\\n function setLength(bytes32 slot, uint length) internal {\\n assembly {\\n sstore(slot, length)\\n }\\n }\\n\\n /// @dev Pushes an address to the array\\n function push(bytes32 slot, address value) internal {\\n uint length = arrayLength(slot);\\n setAt(slot, length, value);\\n setLength(slot, length + 1);\\n }\\n\\n}\\n\",\"keccak256\":\"0x883de721bbf73a85c494e45380b064b91ea2c5cd0b7a777cdacb544575761c8a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n\\nlibrary StringLib {\\n\\n /// @dev Inspired by OraclizeAPI's implementation - MIT license\\n /// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n function toString(uint value) external pure returns (string memory) {\\n return _toString(value);\\n }\\n\\n function _toString(uint value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint temp = value;\\n uint digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n function toAsciiString(address x) external pure returns (string memory) {\\n return _toAsciiString(x);\\n }\\n\\n function _toAsciiString(address x) internal pure returns (string memory) {\\n bytes memory s = new bytes(40);\\n for (uint i = 0; i < 20; i++) {\\n bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i)))));\\n bytes1 hi = bytes1(uint8(b) / 16);\\n bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));\\n s[2 * i] = _char(hi);\\n s[2 * i + 1] = _char(lo);\\n }\\n return string(s);\\n }\\n\\n function char(bytes1 b) external pure returns (bytes1 c) {\\n return _char(b);\\n }\\n\\n function _char(bytes1 b) internal pure returns (bytes1 c) {\\n if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);\\n else return bytes1(uint8(b) + 0x57);\\n }\\n\\n}\\n\",\"keccak256\":\"0xe7fef8dd3d994fd08ac32e3eff07f39546cc58dc0101f5fc7c0efebfb4f3f01a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xcaaf196e5c26fdcd072a9f0833b54cf9fbd12d08be59898f04611f685d31707a\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n * @custom:oz-retyped-from bool\\n */\\n uint8 private _initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private _initializing;\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint8 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n bool isTopLevelCall = !_initializing;\\n require(\\n (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n _initialized = 1;\\n if (isTopLevelCall) {\\n _initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n _initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint8 version) {\\n require(!_initializing && _initialized < version, \\\"Initializable: contract is already initialized\\\");\\n _initialized = version;\\n _initializing = true;\\n _;\\n _initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n require(_initializing, \\\"Initializable: contract is not initializing\\\");\\n _;\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n require(!_initializing, \\\"Initializable: contract is initializing\\\");\\n if (_initialized != type(uint8).max) {\\n _initialized = type(uint8).max;\\n emit Initialized(type(uint8).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint8) {\\n return _initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _initializing;\\n }\\n}\\n\",\"keccak256\":\"0x3c7a20b7e9d134311f43e27990f32c75ff6cb461a6136c4f83fc20734f1d82e0\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/proxy/ControllableV3.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/Initializable.sol\\\";\\nimport \\\"../tools/TetuERC165.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../lib/SlotsLib.sol\\\";\\nimport \\\"../lib/InterfaceIds.sol\\\";\\n\\n/// @title Implement basic functionality for any contract that require strict control\\n/// @dev Can be used with upgradeable pattern.\\n/// Require call __Controllable_init() in any case.\\n/// @author belbix\\nabstract contract ControllableV3 is Initializable, TetuERC165, IControllable {\\n using SlotsLib for bytes32;\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant CONTROLLABLE_VERSION = \\\"3.0.1\\\";\\n\\n bytes32 internal constant _CONTROLLER_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.controller\\\")) - 1);\\n bytes32 internal constant _CREATED_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.created\\\")) - 1);\\n bytes32 internal constant _CREATED_BLOCK_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.created_block\\\")) - 1);\\n bytes32 internal constant _REVISION_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.revision\\\")) - 1);\\n bytes32 internal constant _PREVIOUS_LOGIC_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.prev_logic\\\")) - 1);\\n\\n event ContractInitialized(address controller, uint ts, uint block);\\n event RevisionIncreased(uint value, address oldLogic);\\n\\n /// @dev Prevent implementation init\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initialize contract after setup it as proxy implementation\\n /// Save block.timestamp in the \\\"created\\\" variable\\n /// @dev Use it only once after first logic setup\\n /// @param controller_ Controller address\\n function __Controllable_init(address controller_) internal onlyInitializing {\\n require(controller_ != address(0), \\\"Zero controller\\\");\\n _requireInterface(controller_, InterfaceIds.I_CONTROLLER);\\n require(IController(controller_).governance() != address(0), \\\"Zero governance\\\");\\n _CONTROLLER_SLOT.set(controller_);\\n _CREATED_SLOT.set(block.timestamp);\\n _CREATED_BLOCK_SLOT.set(block.number);\\n emit ContractInitialized(controller_, block.timestamp, block.number);\\n }\\n\\n /// @dev Return true if given address is controller\\n function isController(address _value) public override view returns (bool) {\\n return _value == controller();\\n }\\n\\n /// @notice Return true if given address is setup as governance in Controller\\n function isGovernance(address _value) public override view returns (bool) {\\n return IController(controller()).governance() == _value;\\n }\\n\\n /// @dev Contract upgrade counter\\n function revision() external view returns (uint){\\n return _REVISION_SLOT.getUint();\\n }\\n\\n /// @dev Previous logic implementation\\n function previousImplementation() external view returns (address){\\n return _PREVIOUS_LOGIC_SLOT.getAddress();\\n }\\n\\n /// @dev See {IERC165-supportsInterface}.\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_CONTROLLABLE || super.supportsInterface(interfaceId);\\n }\\n\\n // ************* SETTERS/GETTERS *******************\\n\\n /// @notice Return controller address saved in the contract slot\\n function controller() public view override returns (address) {\\n return _CONTROLLER_SLOT.getAddress();\\n }\\n\\n /// @notice Return creation timestamp\\n /// @return Creation timestamp\\n function created() external view override returns (uint256) {\\n return _CREATED_SLOT.getUint();\\n }\\n\\n /// @notice Return creation block number\\n /// @return Creation block number\\n function createdBlock() external override view returns (uint256) {\\n return _CREATED_BLOCK_SLOT.getUint();\\n }\\n\\n /// @dev Revision should be increased on each contract upgrade\\n function increaseRevision(address oldLogic) external override {\\n require(msg.sender == address(this), \\\"Increase revision forbidden\\\");\\n uint r = _REVISION_SLOT.getUint() + 1;\\n _REVISION_SLOT.set(r);\\n _PREVIOUS_LOGIC_SLOT.set(oldLogic);\\n emit RevisionIncreased(r, oldLogic);\\n }\\n\\n /// @dev Gets a slot as bytes32\\n function getSlot(uint slot) external view returns (bytes32 result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x903c41cf5b652b90c959c47013f8ad949e435ec7e98fd021fef12388c78c05a2\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyBaseV3.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IForwarder.sol\\\";\\nimport \\\"../proxy/ControllableV3.sol\\\";\\nimport \\\"./StrategyLib2.sol\\\";\\n\\n/// @title Abstract contract for base strategy functionality\\n/// @author a17\\nabstract contract StrategyBaseV3 is IStrategyV3, ControllableV3 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Version of this contract. Adjust manually on each code modification.\\n string public constant STRATEGY_BASE_VERSION = \\\"3.0.1\\\";\\n\\n // *************************************************************\\n // VARIABLES\\n // Keep names and ordering!\\n // Add only in the bottom.\\n // *************************************************************\\n\\n BaseState internal baseState;\\n\\n // *************************************************************\\n // INIT\\n // *************************************************************\\n\\n /// @notice Initialize contract after setup it as proxy implementation\\n function __StrategyBase_init(\\n address controller_,\\n address splitter_\\n ) internal onlyInitializing {\\n _requireInterface(splitter_, InterfaceIds.I_SPLITTER);\\n __Controllable_init(controller_);\\n StrategyLib2.init(baseState, controller_, splitter_);\\n }\\n\\n // *************************************************************\\n // VIEWS\\n // *************************************************************\\n\\n /// @dev Total amount of underlying assets under control of this strategy.\\n function totalAssets() public view override returns (uint) {\\n return IERC20(baseState.asset).balanceOf(address(this)) + investedAssets();\\n }\\n\\n /// @dev See {IERC165-supportsInterface}.\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_STRATEGY_V3 || interfaceId == InterfaceIds.I_STRATEGY_V2 || super.supportsInterface(interfaceId);\\n }\\n\\n function asset() external view returns (address) {\\n return baseState.asset;\\n }\\n\\n function splitter() external view returns (address) {\\n return baseState.splitter;\\n }\\n\\n function compoundRatio() external view returns (uint) {\\n return baseState.compoundRatio;\\n }\\n\\n function performanceReceiver() external view returns (address) {\\n return baseState.performanceReceiver;\\n }\\n\\n function performanceFee() external view returns (uint) {\\n return baseState.performanceFee;\\n }\\n\\n function performanceFeeRatio() external view returns (uint) {\\n return baseState.performanceFeeRatio;\\n }\\n\\n function strategySpecificName() external view returns (string memory) {\\n return baseState.strategySpecificName;\\n }\\n\\n // *************************************************************\\n // VOTER ACTIONS\\n // *************************************************************\\n\\n /// @dev PlatformVoter can change compound ratio for some strategies.\\n /// A strategy can implement another logic for some uniq cases.\\n function setCompoundRatio(uint value) external virtual override {\\n StrategyLib2._changeCompoundRatio(baseState, controller(), value);\\n }\\n\\n // *************************************************************\\n // OPERATOR ACTIONS\\n // *************************************************************\\n\\n /// @dev The name will be used for UI.\\n function setStrategySpecificName(string calldata name) external {\\n StrategyLib2.onlyOperators(controller());\\n StrategyLib2._changeStrategySpecificName(baseState, name);\\n }\\n\\n /// @dev In case of any issue operator can withdraw all from pool.\\n function emergencyExit() external {\\n // check inside lib call\\n\\n _emergencyExitFromPool();\\n StrategyLib2.sendOnEmergencyExit(controller(), baseState.asset, baseState.splitter);\\n }\\n\\n /// @dev Manual claim rewards.\\n function claim() external {\\n StrategyLib2._checkManualClaim(controller());\\n _claim();\\n }\\n\\n // *************************************************************\\n // GOVERNANCE ACTIONS\\n // *************************************************************\\n\\n /// @notice Set performance fee, receiver and ratio\\n function setupPerformanceFee(uint fee_, address receiver_, uint ratio_) external {\\n StrategyLib2.setupPerformanceFee(baseState, fee_, receiver_, ratio_, controller());\\n }\\n\\n // *************************************************************\\n // DEPOSIT/WITHDRAW\\n // *************************************************************\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint /*amount_*/,\\n bool updateTotalAssetsBeforeInvest_\\n ) external override returns (\\n uint strategyLoss\\n ) {\\n uint balance = StrategyLib2._checkInvestAll(baseState.splitter, baseState.asset);\\n\\n if (balance > 0) {\\n strategyLoss = _depositToPool(balance, updateTotalAssetsBeforeInvest_);\\n }\\n\\n return strategyLoss;\\n }\\n\\n /// @dev Withdraws all underlying assets to the vault\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external override returns (uint strategyLoss) {\\n address _splitter = baseState.splitter;\\n address _asset = baseState.asset;\\n\\n uint balance = StrategyLib2._checkSplitterSenderAndGetBalance(_splitter, _asset);\\n\\n (uint expectedWithdrewUSD, uint assetPrice, uint _strategyLoss) = _withdrawAllFromPool();\\n\\n StrategyLib2._withdrawAllToSplitterPostActions(\\n _asset,\\n balance,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n return _strategyLoss;\\n }\\n\\n /// @dev Withdraws some assets to the splitter\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external override returns (uint strategyLoss) {\\n address _splitter = baseState.splitter;\\n address _asset = baseState.asset;\\n\\n uint balance = StrategyLib2._checkSplitterSenderAndGetBalance(_splitter, _asset);\\n\\n if (amount > balance) {\\n uint expectedWithdrewUSD;\\n uint assetPrice;\\n\\n (expectedWithdrewUSD, assetPrice, strategyLoss) = _withdrawFromPool(amount - balance);\\n balance = StrategyLib2.checkWithdrawImpact(\\n _asset,\\n balance,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n }\\n\\n StrategyLib2._withdrawToSplitterPostActions(\\n amount,\\n balance,\\n _asset,\\n _splitter\\n );\\n return strategyLoss;\\n }\\n\\n // *************************************************************\\n // VIRTUAL\\n // These functions must be implemented in the strategy contract\\n // *************************************************************\\n\\n /// @dev Amount of underlying assets invested to the pool.\\n function investedAssets() public view virtual returns (uint);\\n\\n /// @notice Deposit given amount to the pool.\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _depositToPool(\\n uint amount,\\n bool updateTotalAssetsBeforeInvest_\\n ) internal virtual returns (\\n uint strategyLoss\\n );\\n\\n /// @dev Withdraw given amount from the pool.\\n /// @return expectedWithdrewUSD Sum of USD value of each asset in the pool that was withdrawn, decimals of {asset}.\\n /// @return assetPrice Price of the strategy {asset}.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _withdrawFromPool(uint amount) internal virtual returns (\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n uint strategyLoss\\n );\\n\\n /// @dev Withdraw all from the pool.\\n /// @return expectedWithdrewUSD Sum of USD value of each asset in the pool that was withdrawn, decimals of {asset}.\\n /// @return assetPrice Price of the strategy {asset}.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _withdrawAllFromPool() internal virtual returns (\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n uint strategyLoss\\n );\\n\\n /// @dev If pool support emergency withdraw need to call it for emergencyExit()\\n /// Withdraw assets without impact checking.\\n function _emergencyExitFromPool() internal virtual;\\n\\n /// @dev Claim all possible rewards.\\n function _claim() internal virtual returns (address[] memory rewardTokens, uint[] memory amounts);\\n\\n /// @dev This empty reserved space is put in place to allow future versions to add new\\n /// variables without shifting down storage in the inheritance chain.\\n /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n uint[50 - 7] private __gap;\\n}\\n\",\"keccak256\":\"0xe38a85a74609ad7047635c8d8fc37a12b4e5731903aa1dcc434a1705c09db06f\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/tools/TetuERC165.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/ERC165.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../lib/InterfaceIds.sol\\\";\\n\\n/// @dev Tetu Implementation of the {IERC165} interface extended with helper functions.\\n/// @author bogdoslav\\nabstract contract TetuERC165 is ERC165 {\\n\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_TETU_ERC165 || super.supportsInterface(interfaceId);\\n }\\n\\n // *************************************************************\\n // HELPER FUNCTIONS\\n // *************************************************************\\n /// @author bogdoslav\\n\\n /// @dev Checks what interface with id is supported by contract.\\n /// @return bool. Do not throws\\n function _isInterfaceSupported(address contractAddress, bytes4 interfaceId) internal view returns (bool) {\\n require(contractAddress != address(0), \\\"Zero address\\\");\\n // check what address is contract\\n uint codeSize;\\n assembly {\\n codeSize := extcodesize(contractAddress)\\n }\\n if (codeSize == 0) return false;\\n\\n try IERC165(contractAddress).supportsInterface(interfaceId) returns (bool isSupported) {\\n return isSupported;\\n } catch {\\n }\\n return false;\\n }\\n\\n /// @dev Checks what interface with id is supported by contract and reverts otherwise\\n function _requireInterface(address contractAddress, bytes4 interfaceId) internal view {\\n require(_isInterfaceSupported(contractAddress, interfaceId), \\\"Interface is not supported\\\");\\n }\\n\\n /// @dev Checks what address is ERC20.\\n /// @return bool. Do not throws\\n function _isERC20(address contractAddress) internal view returns (bool) {\\n require(contractAddress != address(0), \\\"Zero address\\\");\\n // check what address is contract\\n uint codeSize;\\n assembly {\\n codeSize := extcodesize(contractAddress)\\n }\\n if (codeSize == 0) return false;\\n\\n bool totalSupplySupported;\\n try IERC20(contractAddress).totalSupply() returns (uint) {\\n totalSupplySupported = true;\\n } catch {\\n }\\n\\n bool balanceSupported;\\n try IERC20(contractAddress).balanceOf(address(this)) returns (uint) {\\n balanceSupported = true;\\n } catch {\\n }\\n\\n return totalSupplySupported && balanceSupported;\\n }\\n\\n\\n /// @dev Checks what interface with id is supported by contract and reverts otherwise\\n function _requireERC20(address contractAddress) internal view {\\n require(_isERC20(contractAddress), \\\"Not ERC20\\\");\\n }\\n}\\n\",\"keccak256\":\"0xa6eb1009f769fbca986553c7f32af09c9e66c330b4b8c7b8344997001e2cd4f1\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverterCallback.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\n/// @notice TetuConverter sends callback notifications to its user via this interface\\ninterface ITetuConverterCallback {\\n /// @notice Converters calls this function if user should return some amount back.\\n /// f.e. when the health factor is unhealthy and the converter needs more tokens to fix it.\\n /// or when the full repay is required and converter needs to get full amount-to-repay.\\n /// @param asset_ Required asset (either collateral or borrow)\\n /// @param amount_ Required amount of the {asset_}\\n /// @return amountOut Exact amount that borrower has sent to balance of TetuConverter\\n function requirePayAmountBack(address asset_, uint amount_) external returns (uint amountOut);\\n\\n /// @notice TetuConverter calls this function when it sends any amount to user's balance\\n /// @param assets_ Any asset sent to the balance, i.e. inside repayTheBorrow\\n /// @param amounts_ Amount of {asset_} that has been sent to the user's balance\\n function onTransferAmounts(address[] memory assets_, uint[] memory amounts_) external;\\n}\\n\",\"keccak256\":\"0x1ab7657c44e7725e32ef1a25293f1895911943bb25a8d0afb22a218ee4fa9d5b\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3MintCallback.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Callback for IUniswapV3PoolActions#mint\\r\\n/// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface\\r\\ninterface IUniswapV3MintCallback {\\r\\n /// @notice Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint.\\r\\n /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity.\\r\\n /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\\r\\n /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity\\r\\n /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity\\r\\n /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call\\r\\n function uniswapV3MintCallback(\\r\\n uint256 amount0Owed,\\r\\n uint256 amount1Owed,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\",\"keccak256\":\"0xb6253f2c332f5e46e278b90b1c6c44cf392e512a5df3d29fc623c950deca19bf\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedDefaultStateProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Provides access to getDefaultState() of a pair-based strategy\\r\\ninterface IPairBasedDefaultStateProvider {\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n );\\r\\n}\",\"keccak256\":\"0x883b0f9e463485a57aa1baea9aafef64180362d336114a53f6cb8b7a94303d70\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/interfaces/IRebalancingV2Strategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./IPairBasedDefaultStateProvider.sol\\\";\\r\\nimport \\\"./ISetupPairBasedStrategy.sol\\\";\\r\\n\\r\\ninterface IRebalancingV2Strategy is IPairBasedDefaultStateProvider, ISetupPairBasedStrategy {\\r\\n function needRebalance() external view returns (bool);\\r\\n\\r\\n /// @notice Rebalance using borrow/repay only, no swaps\\r\\n /// @param checkNeedRebalance Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\\r\\n function rebalanceNoSwaps(bool checkNeedRebalance) external;\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n function quoteWithdrawByAgg(bytes memory planEntryData) external returns (address tokenToSwap, uint amountToSwap);\\r\\n\\r\\n /// @notice Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool]\\r\\n /// Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt.\\r\\n /// You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\\r\\n /// @dev All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\\r\\n /// @param tokenToSwap_ What token should be swapped to other\\r\\n /// @param aggregator_ Aggregator that should be used on next swap. 0 - use liquidator\\r\\n /// @param amountToSwap_ Amount that should be swapped. 0 - no swap\\r\\n /// @param swapData Swap rote that was prepared off-chain.\\r\\n /// @param planEntryData PLAN_XXX + additional data, see IterationPlanKinds\\r\\n /// @param entryToPool Allow to enter to the pool at the end. Use false if you are going to make several iterations.\\r\\n /// It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment\\r\\n /// 0 - not allowed, 1 - allowed, 2 - allowed only if completed\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions.\\r\\n function withdrawByAggStep(\\r\\n address tokenToSwap_,\\r\\n address aggregator_,\\r\\n uint amountToSwap_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n uint entryToPool\\r\\n ) external returns (bool completed);\\r\\n\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x1ae39d0cc7607cdb9b935e2f6bcb8db8206f180d17fc2230f368509c5173d788\",\"license\":\"MIT\"},\"contracts/interfaces/ISetupPairBasedStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Functions to initialize pair-based strategies\\r\\ninterface ISetupPairBasedStrategy {\\r\\n\\r\\n /// @notice Manually set status of the fuse\\r\\n /// @param status See PairBasedStrategyLib.FuseStatus enum for possible values\\r\\n function setFuseStatus(uint status) external;\\r\\n\\r\\n /// @notice Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n /// @param values Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function setFuseThresholds(uint[4] memory values) external;\\r\\n function setStrategyProfitHolder(address strategyProfitHolder) external;\\r\\n\\r\\n /// @notice Set withdrawDone value.\\r\\n /// When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying.\\r\\n /// After completion of the conversion withdrawDone can be set to 1.\\r\\n /// So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\\r\\n /// @param done 0 - full withdraw required, 1 - full withdraw was done\\r\\n function setWithdrawDone(uint done) external;\\r\\n}\\r\\n\",\"keccak256\":\"0xbe3f6fdf20e05b353202bfd42cb087c106ac055310fb3af80b56a4cda2a86a79\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppPlatforms.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary AppPlatforms {\\r\\n string public constant UNIV3 = \\\"UniswapV3\\\";\\r\\n string public constant BALANCER = \\\"Balancer\\\";\\r\\n string public constant ALGEBRA = \\\"Algebra\\\";\\r\\n string public constant KYBER = \\\"Kyber\\\";\\r\\n string public constant PANCAKE = \\\"Pancake\\\"; // https://pancakeswap.finance/\\r\\n}\\r\\n\",\"keccak256\":\"0x28767f209dd412f52bc6274d3d95e4fb1fc03f6e8db183c13efd09ed82741b4b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyBaseV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverterCallback.sol\\\";\\r\\nimport \\\"./ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"./DepositorBase.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/////////////////////////////////////////////////////////////////////\\r\\n/// TERMS\\r\\n/// Main asset == underlying: the asset deposited to the vault by users\\r\\n/// Secondary assets: all assets deposited to the internal pool except the main asset\\r\\n/////////////////////////////////////////////////////////////////////\\r\\n// History:\\r\\n// 3.0.1 refactoring of emergency exit\\r\\n// 3.1.0 use bookkeeper, new set of events\\r\\n// 3.1.2 scb-867\\r\\n// 3.1.3,4 scb-900, scb-914\\r\\n// 3.1.5 use approveForced for aggregators\\r\\n\\r\\n/// @title Abstract contract for base Converter strategy functionality\\r\\n/// @notice All depositor assets must be correlated (ie USDC/USDT/DAI)\\r\\n/// @author bogdoslav, dvpublic, a17\\r\\nabstract contract ConverterStrategyBase is IConverterStrategyBase, ITetuConverterCallback, DepositorBase, StrategyBaseV3 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region -------------------------------------------------------- DATA TYPES\\r\\n struct WithdrawUniversalLocal {\\r\\n ITetuConverter converter;\\r\\n /// @notice Target asset that should be received on balance.\\r\\n /// It's underlying in _withdrawUniversal(), but it can be any other asset in requirePayAmountBack()\\r\\n address theAsset;\\r\\n /// @notice List of tokens received by _depositorPoolAssets()\\r\\n address[] tokens;\\r\\n /// @notice Index of the {asset} in {tokens}\\r\\n uint indexTheAsset;\\r\\n /// @notice Initial balance of the [asset}\\r\\n uint balanceBefore;\\r\\n uint indexUnderlying;\\r\\n }\\r\\n //endregion -------------------------------------------------------- DATA TYPES\\r\\n\\r\\n //region -------------------------------------------------------- CONSTANTS\\r\\n\\r\\n /// @dev Version of this contract. Adjust manually on each code modification.\\r\\n string public constant CONVERTER_STRATEGY_BASE_VERSION = \\\"3.1.5\\\";\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n /// @notice If we need to withdraw A, we always tries to receive on balance A + delta\\r\\n /// and have at least delta on balance after withdraw to prevent situation when we have debts\\r\\n /// but don't have any liquidity to pay the debts and receive locked collaterals back\\r\\n ///\\r\\n /// Delta will be in the range [GAP_WITHDRAW...2 * GAP_WITHDRAW]\\r\\n uint internal constant GAP_WITHDRAW = 1_000;\\r\\n //endregion -------------------------------------------------------- CONSTANTS\\r\\n\\r\\n //region -------------------------------------------------------- VARIABLES\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n // Keep names and ordering!\\r\\n // Add only in the bottom and don't forget to decrease gap variable\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Minimum token amounts that can be liquidated\\r\\n /// @dev These thresholds are used to workaround dust problems in many other cases, not during liquidation only\\r\\n mapping(address => uint) public liquidationThresholds;\\r\\n\\r\\n /// @notice Internal variables of ConverterStrategyBase\\r\\n ConverterStrategyBaseState internal _csbs;\\r\\n //endregion -------------------------------------------------------- VARIABLES\\r\\n\\r\\n //region -------------------------------------------------------- Getters\\r\\n function converter() external view returns (ITetuConverter) {\\r\\n return _csbs.converter;\\r\\n }\\r\\n\\r\\n function reinvestThresholdPercent() external view returns (uint) {\\r\\n return _csbs.reinvestThresholdPercent;\\r\\n }\\r\\n\\r\\n function debtToInsurance() external view returns (int) {\\r\\n return _csbs.debtToInsurance;\\r\\n }\\r\\n //endregion -------------------------------------------------------- Getters\\r\\n\\r\\n //region -------------------------------------------------------- Events\\r\\n event OnDepositorEnter(uint[] amounts, uint[] consumedAmounts);\\r\\n event OnDepositorExit(uint liquidityAmount, uint[] withdrawnAmounts);\\r\\n event OnDepositorEmergencyExit(uint[] withdrawnAmounts);\\r\\n event OnHardWorkEarnedLost(\\r\\n uint investedAssetsNewPrices,\\r\\n uint earnedByPrices,\\r\\n uint earnedHandleRewards,\\r\\n uint lostHandleRewards,\\r\\n uint earnedDeposit,\\r\\n uint lostDeposit,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n );\\r\\n //endregion -------------------------------------------------------- Events\\r\\n\\r\\n //region -------------------------------------------------------- Initialization and configuration\\r\\n\\r\\n /// @notice Initialize contract after setup it as proxy implementation\\r\\n function __ConverterStrategyBase_init(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address converter_\\r\\n ) internal onlyInitializing {\\r\\n __StrategyBase_init(controller_, splitter_);\\r\\n _csbs.converter = ITetuConverter(converter_);\\r\\n\\r\\n // 1% by default\\r\\n _csbs.reinvestThresholdPercent = DENOMINATOR / 100;\\r\\n emit ConverterStrategyBaseLib2.ReinvestThresholdPercentChanged(DENOMINATOR / 100);\\r\\n }\\r\\n\\r\\n /// @dev Liquidation thresholds are used to detect dust in many cases, not only in liquidation case\\r\\n /// @param amount Min amount of token allowed to liquidate, token's decimals are used.\\r\\n function setLiquidationThreshold(address token, uint amount) external {\\r\\n ConverterStrategyBaseLib2.checkLiquidationThresholdChanged(controller(), token, amount);\\r\\n liquidationThresholds[token] = amount;\\r\\n }\\r\\n\\r\\n /// @param percent_ New value of the percent, decimals = {REINVEST_THRESHOLD_PERCENT_DENOMINATOR}\\r\\n function setReinvestThresholdPercent(uint percent_) external {\\r\\n ConverterStrategyBaseLib2.checkReinvestThresholdPercentChanged(controller(), percent_);\\r\\n _csbs.reinvestThresholdPercent = percent_;\\r\\n }\\r\\n //endregion -------------------------------------------------------- Initialization and configuration\\r\\n\\r\\n //region -------------------------------------------------------- Deposit to the pool\\r\\n\\r\\n /// @notice Amount of underlying assets converted to pool assets and invested to the pool.\\r\\n function investedAssets() override public view virtual returns (uint) {\\r\\n return _csbs.investedAssets;\\r\\n }\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n function _depositToPool(uint amount_, bool updateTotalAssetsBeforeInvest_) override internal virtual returns (\\r\\n uint strategyLoss\\r\\n ){\\r\\n (uint updatedInvestedAssets, uint earnedByPrices) = _fixPriceChanges(updateTotalAssetsBeforeInvest_);\\r\\n (strategyLoss,,,) = _depositToPoolUniversal(amount_, earnedByPrices, updatedInvestedAssets);\\r\\n }\\r\\n\\r\\n /// @notice Deposit {amount_} to the pool, send {earnedByPrices_} to insurance.\\r\\n /// totalAsset will decrease on earnedByPrices_ and sharePrice won't change after all recalculations.\\r\\n /// @dev We need to deposit {amount_} and withdraw {earnedByPrices_} here\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param earnedByPrices_ Profit received because of price changing\\r\\n /// @param investedAssets_ Invested assets value calculated with updated prices\\r\\n /// @return strategyLoss Loss happened on the depositing. It doesn't include any price-changing losses\\r\\n /// @return amountSentToInsurance Price-changing-profit that was sent to the insurance\\r\\n /// @return investedAssetsAfter Value of csbs.investedAssets after the call of the function\\r\\n /// @return balanceAfter Balance of the underlying after the call of the function\\r\\n function _depositToPoolUniversal(uint amount_, uint earnedByPrices_, uint investedAssets_) internal virtual returns (\\r\\n uint strategyLoss,\\r\\n uint amountSentToInsurance,\\r\\n uint investedAssetsAfter,\\r\\n uint balanceAfter\\r\\n ){\\r\\n address _asset = baseState.asset;\\r\\n\\r\\n uint amountToDeposit = amount_ > earnedByPrices_\\r\\n ? amount_ - earnedByPrices_\\r\\n : 0;\\r\\n\\r\\n // skip deposit for small amounts\\r\\n bool needToDeposit = amountToDeposit > _csbs.reinvestThresholdPercent * investedAssets_ / DENOMINATOR;\\r\\n uint balanceBefore = AppLib.balance(_asset);\\r\\n\\r\\n // send earned-by-prices to the insurance, ignore dust values\\r\\n if (earnedByPrices_ > AppLib._getLiquidationThreshold(liquidationThresholds[_asset])) {\\r\\n if (needToDeposit || balanceBefore >= earnedByPrices_) {\\r\\n (amountSentToInsurance,) = ConverterStrategyBaseLib2.sendToInsurance(\\r\\n _asset,\\r\\n earnedByPrices_,\\r\\n baseState.splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceBefore\\r\\n );\\r\\n } else {\\r\\n // needToDeposit is false and we don't have enough amount to cover earned-by-prices, we need to withdraw\\r\\n (,, strategyLoss, amountSentToInsurance) = _withdrawUniversal(0, earnedByPrices_, investedAssets_);\\r\\n }\\r\\n }\\r\\n\\r\\n // make deposit\\r\\n if (needToDeposit) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(_asset);\\r\\n\\r\\n // prepare array of amounts ready to deposit, borrow missed amounts\\r\\n uint[] memory amounts = _beforeDeposit(_csbs.converter, amountToDeposit, tokens, indexAsset);\\r\\n\\r\\n // make deposit, actually consumed amounts can be different from the desired amounts\\r\\n if (!ConverterStrategyBaseLib2.findZeroAmount(amounts)) {\\r\\n // we cannot enter to pool if at least one of amounts is zero\\r\\n // we check != 0 and don't use thresholds because some strategies allow to enter to the pool with amount < liquidation threshold\\r\\n (uint[] memory consumedAmounts,) = _depositorEnter(amounts);\\r\\n emit OnDepositorEnter(amounts, consumedAmounts);\\r\\n }\\r\\n }\\r\\n\\r\\n // update _investedAssets with new deposited amount\\r\\n investedAssetsAfter = _updateInvestedAssets();\\r\\n balanceAfter = AppLib.balance(_asset);\\r\\n\\r\\n // we need to compensate difference if during deposit we lost some assets\\r\\n (,strategyLoss) = ConverterStrategyBaseLib2._registerIncome(\\r\\n investedAssets_ + balanceBefore,\\r\\n investedAssetsAfter + balanceAfter + amountSentToInsurance\\r\\n );\\r\\n\\r\\n return (strategyLoss, amountSentToInsurance, investedAssetsAfter, balanceAfter);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Deposit to the pool\\r\\n\\r\\n //region -------------------------------------------------------- Convert amounts before deposit\\r\\n\\r\\n /// @notice Prepare {tokenAmounts} to be passed to depositorEnter\\r\\n /// @dev Override this function to customize entry kind\\r\\n /// @param amount_ The amount of main asset that should be invested\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmounts Amounts of depositor's assets ready to invest (this array can be passed to depositorEnter)\\r\\n function _beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_\\r\\n ) internal virtual returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // calculate required collaterals for each token and temporary save them to tokenAmounts\\r\\n (uint[] memory weights, uint totalWeight) = _depositorPoolWeights();\\r\\n return ConverterStrategyBaseLib.beforeDeposit(\\r\\n converter_,\\r\\n amount_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n weights,\\r\\n totalWeight,\\r\\n liquidationThresholds\\r\\n );\\r\\n }\\r\\n //endregion -------------------------------------------------------- Convert amounts before deposit\\r\\n\\r\\n //region -------------------------------------------------------- Get requested amount\\r\\n\\r\\n /// @notice Initialize members of {v}\\r\\n /// @param underlying true if asset_ is underlying\\r\\n function _initWithdrawUniversalLocal(address asset_, WithdrawUniversalLocal memory v, bool underlying) internal view {\\r\\n v.tokens = _depositorPoolAssets();\\r\\n v.theAsset = asset_;\\r\\n v.converter = _csbs.converter;\\r\\n v.indexTheAsset = AppLib.getAssetIndex(v.tokens, asset_);\\r\\n v.balanceBefore = AppLib.balance(asset_);\\r\\n v.indexUnderlying = underlying ? v.indexTheAsset : AppLib.getAssetIndex(v.tokens, baseState.asset);\\r\\n }\\r\\n\\r\\n /// @notice Get the specified {amount} of the given {v.asset} on the balance\\r\\n /// @dev Ensures that either all debts are closed, or a non-zero amount remains on the balance or in the pool to pay off the debts\\r\\n /// @param amount_ Required amount of {v.asset}. Use type(uint).max to withdraw all\\r\\n /// @return expectedTotalAssetAmount Expected amount of {v.asset} that should be received on the balance\\r\\n /// Expected total amount of given asset after all withdraws, conversions, swaps and repays\\r\\n function _makeRequestedAmount(uint amount_, WithdrawUniversalLocal memory v) internal virtual returns ( // it's virtual to simplify unit testing\\r\\n uint expectedTotalAssetAmount\\r\\n ) {\\r\\n uint depositorLiquidity = _depositorLiquidity();\\r\\n\\r\\n // calculate how much liquidity we need to withdraw for getting at least requested amount of the {v.asset}\\r\\n uint[] memory quoteAmounts = _depositorQuoteExit(depositorLiquidity);\\r\\n uint liquidityAmountToWithdraw = ConverterStrategyBaseLib2.getLiquidityAmount(\\r\\n amount_,\\r\\n v.tokens,\\r\\n v.indexTheAsset,\\r\\n v.converter,\\r\\n quoteAmounts,\\r\\n depositorLiquidity,\\r\\n v.indexUnderlying\\r\\n );\\r\\n\\r\\n if (liquidityAmountToWithdraw != 0) {\\r\\n uint[] memory withdrawnAmounts = _depositorExit(liquidityAmountToWithdraw, false);\\r\\n // the depositor is able to use less liquidity than it was asked, i.e. Balancer-depositor leaves some BPT unused\\r\\n // use what exactly was withdrew instead of the expectation\\r\\n // assume that liquidity cannot increase in _depositorExit\\r\\n liquidityAmountToWithdraw = depositorLiquidity - _depositorLiquidity();\\r\\n emit OnDepositorExit(liquidityAmountToWithdraw, withdrawnAmounts);\\r\\n }\\r\\n\\r\\n // try to receive at least requested amount of the {v.asset} on the balance\\r\\n uint expectedBalance = ConverterStrategyBaseLib.makeRequestedAmount(\\r\\n v.tokens,\\r\\n v.indexTheAsset,\\r\\n v.converter,\\r\\n AppLib._getLiquidator(controller()),\\r\\n (amount_ == type(uint).max ? amount_ : v.balanceBefore + amount_), // current balance + the amount required to be withdrawn on balance\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n require(expectedBalance >= v.balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n return expectedBalance - v.balanceBefore;\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------------- Get requested amount\\r\\n\\r\\n //region -------------------------------------------------------- Withdraw from the pool\\r\\n\\r\\n function _beforeWithdraw(uint /*amount*/) internal virtual {\\r\\n // do nothing\\r\\n }\\r\\n\\r\\n /// @notice Withdraw given amount from the pool.\\r\\n /// @param amount Amount to be withdrawn in terms of the asset in addition to the exist balance.\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing (in USD, decimals of the {asset})\\r\\n /// @return assetPrice Price of the {asset} from the price oracle\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _withdrawFromPool(uint amount) override internal virtual returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss\\r\\n ) {\\r\\n // calculate profit/loss because of price changes, try to compensate the loss from the insurance\\r\\n (uint investedAssetsNewPrices, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n (expectedWithdrewUSD, assetPrice, strategyLoss,) = _withdrawUniversal(amount, earnedByPrices, investedAssetsNewPrices);\\r\\n }\\r\\n\\r\\n /// @notice Withdraw all from the pool.\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing\\r\\n /// @return assetPrice Price of the {asset} taken from the price oracle\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _withdrawAllFromPool() override internal virtual returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss\\r\\n ) {\\r\\n return _withdrawFromPool(type(uint).max);\\r\\n }\\r\\n\\r\\n /// @dev The function is virtual to simplify unit testing\\r\\n /// @param amount_ Amount to be trying to withdrawn. Max uint means attempt to withdraw all possible invested assets.\\r\\n /// @param earnedByPrices_ Additional amount that should be withdrawn and send to the insurance\\r\\n /// @param investedAssets_ Value of invested assets recalculated using current prices\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing in terms of USD value of each asset in the pool\\r\\n /// @return assetPrice Price of the {asset} taken from the price oracle\\r\\n /// @return strategyLoss Loss before withdrawing: [new-investedAssets - old-investedAssets]\\r\\n /// @return amountSentToInsurance Actual amount of underlying sent to the insurance\\r\\n function _withdrawUniversal(uint amount_, uint earnedByPrices_, uint investedAssets_) virtual internal returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss,\\r\\n uint amountSentToInsurance\\r\\n ) {\\r\\n // amount to withdraw; we add a little gap to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n uint amount = amount_ == type(uint).max\\r\\n ? amount_\\r\\n : (amount_ + earnedByPrices_) * (DENOMINATOR + GAP_WITHDRAW) / DENOMINATOR;\\r\\n _beforeWithdraw(amount);\\r\\n\\r\\n if (amount != 0 && investedAssets_ != 0) {\\r\\n WithdrawUniversalLocal memory v;\\r\\n _initWithdrawUniversalLocal(baseState.asset, v, true);\\r\\n\\r\\n // get at least requested amount of the underlying on the balance\\r\\n assetPrice = ConverterStrategyBaseLib2.getAssetPriceFromConverter(v.converter, v.theAsset);\\r\\n expectedWithdrewUSD = AppLib.sub0(_makeRequestedAmount(amount, v), earnedByPrices_) * assetPrice / 1e18;\\r\\n\\r\\n (amountSentToInsurance, strategyLoss) = ConverterStrategyBaseLib2.calculateIncomeAfterWithdraw(\\r\\n baseState.splitter,\\r\\n v.theAsset,\\r\\n investedAssets_,\\r\\n v.balanceBefore,\\r\\n earnedByPrices_,\\r\\n _updateInvestedAssets()\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n expectedWithdrewUSD,\\r\\n assetPrice,\\r\\n strategyLoss,\\r\\n amountSentToInsurance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Withdraw all amounts from the pool using minimum actions (it skips claiming rewards, fees and so on)\\r\\n function _emergencyExitFromPool() override internal virtual {\\r\\n uint[] memory withdrawnAmounts = _depositorEmergencyExit();\\r\\n emit OnDepositorEmergencyExit(withdrawnAmounts);\\r\\n // we don't convert amounts to main asset to avoid any excess actions\\r\\n // update of invested assets is necessary in any case\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n //endregion -------------------------------------------------------- Withdraw from the pool\\r\\n\\r\\n //region -------------------------------------------------------- Claim rewards\\r\\n\\r\\n /// @notice Claim all possible rewards.\\r\\n function _claim() override internal virtual returns (address[] memory rewardTokensOut, uint[] memory amountsOut) {\\r\\n // get rewards from the Depositor\\r\\n (address[] memory rewardTokens, uint[] memory rewardAmounts, uint[] memory balancesBefore) = _depositorClaimRewards();\\r\\n\\r\\n (rewardTokensOut, amountsOut) = ConverterStrategyBaseLib2.claimConverterRewards(\\r\\n _csbs.converter,\\r\\n _depositorPoolAssets(),\\r\\n rewardTokens,\\r\\n rewardAmounts,\\r\\n balancesBefore\\r\\n );\\r\\n }\\r\\n\\r\\n /// @dev Call recycle process and send tokens to forwarder.\\r\\n /// Need to be separated from the claim process - the claim can be called by operator for other purposes.\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Total performance fee in terms of underlying\\r\\n function _rewardsLiquidation(address[] memory rewardTokens_, uint[] memory rewardAmounts_) internal returns (\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n ) {\\r\\n if (rewardTokens_.length != 0) {\\r\\n (paidDebtToInsurance, amountPerf) = ConverterStrategyBaseLib.recycle(\\r\\n baseState,\\r\\n _csbs,\\r\\n _depositorPoolAssets(),\\r\\n controller(),\\r\\n liquidationThresholds,\\r\\n rewardTokens_,\\r\\n rewardAmounts_\\r\\n );\\r\\n }\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Claim rewards\\r\\n\\r\\n //region -------------------------------------------------------- Hardwork\\r\\n\\r\\n /// @notice A virtual handler to make any action before hardwork\\r\\n /// @return True if the hardwork should be skipped\\r\\n function _preHardWork(bool reInvest) internal virtual returns (bool) {\\r\\n reInvest; // hide warning\\r\\n return false;\\r\\n }\\r\\n\\r\\n /// @notice A virtual handler to make any action after hardwork\\r\\n function _postHardWork() internal virtual {}\\r\\n\\r\\n /// @notice Is strategy ready to hard work\\r\\n function isReadyToHardWork() override external virtual view returns (bool) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n return true;\\r\\n }\\r\\n\\r\\n /// @notice Do hard work with reinvesting\\r\\n /// @return earned Earned amount in terms of {asset}\\r\\n /// @return lost Lost amount in terms of {asset}\\r\\n function doHardWork() override public returns (uint earned, uint lost) {\\r\\n require(msg.sender == baseState.splitter, StrategyLib2.DENIED);\\r\\n return _doHardWork(true);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards, do _processClaims() after claiming, calculate earned and lost amounts\\r\\n /// @return earned The amount of earned rewards.\\r\\n /// @return lost The amount of lost rewards.\\r\\n /// @return assetBalanceAfterClaim The asset balance after claiming rewards.\\r\\n /// @return paidDebtToInsurance A part of {earned} spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function _handleRewards() internal virtual returns (\\r\\n uint earned,\\r\\n uint lost,\\r\\n uint assetBalanceAfterClaim,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n );\\r\\n\\r\\n /// @param reInvest Deposit to pool all available amount if it's greater than the threshold\\r\\n /// @return earned Earned amount in terms of {asset}\\r\\n /// @return lost Lost amount in terms of {asset}\\r\\n function _doHardWork(bool reInvest) internal returns (uint earned, uint lost) {\\r\\n // ATTENTION! splitter will not cover the loss if it is lower than profit\\r\\n (uint investedAssetsNewPrices, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n\\r\\n if (!_preHardWork(reInvest)) {\\r\\n // claim rewards and get current asset balance\\r\\n (uint earned1, uint lost1, uint assetBalance, uint paidDebtToInsurance, uint amountPerf) = _handleRewards();\\r\\n\\r\\n // re-invest income\\r\\n (uint investedAssetsAfterHandleRewards,,) = _calcInvestedAssets();\\r\\n\\r\\n { // send earnedByPrices to the insurance, optionally make deposit (and even withdraw if necessary)\\r\\n (, uint amountSentToInsurance, uint investedAssetsAfterDeposit, uint balanceAfterDeposit) = _depositToPoolUniversal(\\r\\n reInvest\\r\\n && investedAssetsAfterHandleRewards != 0\\r\\n && assetBalance > _csbs.reinvestThresholdPercent * investedAssetsAfterHandleRewards / DENOMINATOR\\r\\n ? assetBalance\\r\\n : 0,\\r\\n earnedByPrices,\\r\\n investedAssetsAfterHandleRewards\\r\\n );\\r\\n\\r\\n (earned, lost) = ConverterStrategyBaseLib2._registerIncome(\\r\\n investedAssetsAfterHandleRewards + assetBalance, // assets in use before deposit\\r\\n investedAssetsAfterDeposit + balanceAfterDeposit + amountSentToInsurance // assets in use after deposit\\r\\n );\\r\\n }\\r\\n\\r\\n _postHardWork();\\r\\n emit OnHardWorkEarnedLost(investedAssetsNewPrices, earnedByPrices, earned1, lost1, earned, lost, paidDebtToInsurance, amountPerf);\\r\\n\\r\\n // Excluded from earned two values: performance fee and amount paid to cover debt before the insurance\\r\\n // Amount sent to the forwarder is still included to the result earned amount.\\r\\n earned = AppLib.sub0(earned + earned1, paidDebtToInsurance + amountPerf);\\r\\n lost += lost1;\\r\\n }\\r\\n\\r\\n // register amount paid for the debts and amount received for the provided collaterals\\r\\n ConverterStrategyBaseLib2.registerBorrowResults(_csbs.converter, baseState.asset);\\r\\n\\r\\n return (earned, lost);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Hardwork\\r\\n\\r\\n //region -------------------------------------------------------- InvestedAssets Calculations\\r\\n\\r\\n /// @notice Updates cached _investedAssets to actual value\\r\\n /// @dev Should be called after deposit / withdraw / claim; virtual - for ut\\r\\n function _updateInvestedAssets() internal returns (uint investedAssetsOut) {\\r\\n (investedAssetsOut,,) = _calcInvestedAssets();\\r\\n _csbs.investedAssets = investedAssetsOut;\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @return amountOut Invested asset amount under control (in terms of {asset})\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets() internal returns (uint amountOut, uint[] memory prices, uint[] memory decs) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(baseState.asset);\\r\\n return ConverterStrategyBaseLib2.calcInvestedAssets(\\r\\n tokens,\\r\\n _getDepositorQuoteExitAmountsOut(tokens),\\r\\n indexAsset,\\r\\n _csbs.converter,\\r\\n true\\r\\n );\\r\\n }\\r\\n\\r\\n function calcInvestedAssets() external returns (uint investedAssetsOut) {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n (investedAssetsOut,,) = _calcInvestedAssets();\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount of deposited tokens that can be received from the pool after withdrawing all liquidity.\\r\\n function _getDepositorQuoteExitAmountsOut(address[] memory tokens) internal returns (\\r\\n uint[] memory depositorQuoteExitAmountsOut\\r\\n ) {\\r\\n uint liquidity = _depositorLiquidity();\\r\\n return liquidity == 0\\r\\n ? new uint[](tokens.length)\\r\\n : _depositorQuoteExit(liquidity);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing. Try to cover the loss, send the profit to the insurance\\r\\n /// @param updateInvestedAssetsAmount_ If false - just return current value of invested assets\\r\\n /// @return investedAssetsOut Updated value of {_investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n /// It's too dangerous to try to get this amount here because of the problem \\\"borrow-repay is not allowed in a single block\\\"\\r\\n /// So, we need to handle it in the caller code.\\r\\n function _fixPriceChanges(bool updateInvestedAssetsAmount_) internal returns (uint investedAssetsOut, uint earnedOut) {\\r\\n if (updateInvestedAssetsAmount_) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(baseState.asset);\\r\\n (investedAssetsOut, earnedOut) = ConverterStrategyBaseLib2.fixPriceChanges(\\r\\n _csbs,\\r\\n baseState,\\r\\n _getDepositorQuoteExitAmountsOut(tokens),\\r\\n tokens,\\r\\n indexAsset\\r\\n );\\r\\n } else {\\r\\n (investedAssetsOut, earnedOut) = (_csbs.investedAssets, 0);\\r\\n }\\r\\n }\\r\\n //endregion -------------------------------------------------------- InvestedAssets Calculations\\r\\n\\r\\n //region -------------------------------------------------------- ITetuConverterCallback\\r\\n\\r\\n /// @notice Converters asks to send some amount back.\\r\\n /// The results depend on whether the required amount is on the balance:\\r\\n /// 1. The {amount_} exists on the balance: send the amount to TetuConverter, return {amount_}\\r\\n /// 2. The {amount_} doesn't exist on the balance. Try to receive the {amount_}.\\r\\n /// 2.1. if the required amount is received: return {amount_}\\r\\n /// 2.2. if less amount X (X < {amount_}) is received return X - gap\\r\\n /// In the case 2 no amount is send to TetuConverter.\\r\\n /// Converter should make second call of requirePayAmountBack({amountOut}) to receive the assets.\\r\\n /// @param theAsset_ Required asset (either collateral or borrow), it can be NOT underlying\\r\\n /// @param amount_ Required amount of {theAsset_}\\r\\n /// @return amountOut Amount that was send OR can be claimed on the next call.\\r\\n /// The caller should control own balance to know if the amount was actually send\\r\\n /// (because we need compatibility with exist not-NSR strategies)\\r\\n function requirePayAmountBack(address theAsset_, uint amount_) external override returns (uint amountOut) {\\r\\n WithdrawUniversalLocal memory v;\\r\\n _initWithdrawUniversalLocal(theAsset_, v, false);\\r\\n require(msg.sender == address(v.converter), StrategyLib.DENIED);\\r\\n require(amount_ != 0, AppErrors.ZERO_VALUE);\\r\\n require(v.indexTheAsset != type(uint).max, AppErrors.WRONG_ASSET);\\r\\n\\r\\n (uint _investedAssets, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n v.balanceBefore = ConverterStrategyBaseLib2.sendProfitGetAssetBalance(theAsset_, v.balanceBefore, _investedAssets, earnedByPrices, baseState);\\r\\n\\r\\n // amount to withdraw; we add a little gap to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n // At first we add only 1 gap.\\r\\n // This is min allowed amount that we should have on balance to be able to send {amount_} to the converter\\r\\n uint amountPlusGap = amount_ * (DENOMINATOR + GAP_WITHDRAW) / DENOMINATOR;\\r\\n\\r\\n if (v.balanceBefore >= amountPlusGap) {\\r\\n // the requested amount is available, send it to the converter\\r\\n IERC20(theAsset_).safeTransfer(address(v.converter), amount_);\\r\\n amountOut = amount_;\\r\\n } else {\\r\\n // the requested amount is not available\\r\\n // so, we cannot send anything to converter in this call\\r\\n // try to receive requested amount to balance\\r\\n // we should receive amount with extra gap, where gap is in the range (GAP_WITHDRAW, 2 * GAP_WITHDRAW]\\r\\n // The caller will be able to claim requested amount (w/o extra gap) in the next call\\r\\n if (_investedAssets == 0) {\\r\\n // there are no invested amounts, we can use amount on balance only\\r\\n // but we cannot send all amount, we should keep not zero amount on balance\\r\\n // to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n // as soon as the converter asks for payment, we still have an opened debt..\\r\\n amountOut = v.balanceBefore * DENOMINATOR / (DENOMINATOR + GAP_WITHDRAW);\\r\\n } else {\\r\\n uint amountTwoGaps = amount_ * (DENOMINATOR + 2 * GAP_WITHDRAW) / DENOMINATOR;\\r\\n // get at least requested amount of {theAsset_} on the balance\\r\\n _makeRequestedAmount(amountTwoGaps - v.balanceBefore, v);\\r\\n\\r\\n uint balanceAfter = AppLib.balance(theAsset_);\\r\\n amountOut = balanceAfter > amountPlusGap\\r\\n ? amount_\\r\\n : balanceAfter * DENOMINATOR / (DENOMINATOR + GAP_WITHDRAW);\\r\\n }\\r\\n }\\r\\n\\r\\n // update invested assets anyway, even if we suppose it will be called in other places\\r\\n _updateInvestedAssets();\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n\\r\\n /// @notice TetuConverter calls this function when it sends any amount to user's balance\\r\\n /// @param assets_ Any asset sent to the balance, i.e. inside repayTheBorrow\\r\\n /// @param amounts_ Amount of {asset_} that has been sent to the user's balance\\r\\n function onTransferAmounts(address[] memory assets_, uint[] memory amounts_) external override {\\r\\n require(msg.sender == address(_csbs.converter), StrategyLib2.DENIED);\\r\\n require(assets_.length == amounts_.length, AppErrors.INCORRECT_LENGTHS);\\r\\n\\r\\n // TetuConverter is able two call this function in two cases:\\r\\n // 1) rebalancing (the health factor of some borrow is too low)\\r\\n // 2) forcible closing of the borrow\\r\\n // In both cases we update invested assets value here\\r\\n // and avoid fixing any related losses in hardwork\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n //endregion -------------------------------------------------------- ITetuConverterCallback\\r\\n\\r\\n //region -------------------------------------------------------- Others\\r\\n\\r\\n /// @notice Unlimited capacity by default\\r\\n function capacity() external virtual view returns (uint) {\\r\\n return 2 ** 255;\\r\\n // almost same as type(uint).max but more gas efficient\\r\\n }\\r\\n\\r\\n /// @return tokens Result of {_depositorPoolAssets}\\r\\n /// @return indexAsset Index of the underlying in {tokens}\\r\\n function _getTokens(address asset_) internal view returns (address[] memory tokens, uint indexAsset) {\\r\\n tokens = _depositorPoolAssets();\\r\\n indexAsset = AppLib.getAssetIndex(tokens, asset_);\\r\\n require(indexAsset != type(uint).max, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Others\\r\\n\\r\\n\\r\\n /// @dev This empty reserved space is put in place to allow future versions to add new\\r\\n /// variables without shifting down storage in the inheritance chain.\\r\\n /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\r\\n uint[50 - 4] private __gap; // 50 - count of variables\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0xad98690d6b244c7012cac7b8e8da330914c11e0f2bd3cc3cf0502bedc1647807\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/DepositorBase.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Abstract base Depositor contract.\\r\\n/// @notice Converter strategies should inherit xDepositor.\\r\\n/// @notice All communication with external pools should be done at inherited contract\\r\\n/// @author bogdoslav\\r\\nabstract contract DepositorBase {\\r\\n\\r\\n /// @notice Returns pool assets\\r\\n function _depositorPoolAssets() internal virtual view returns (address[] memory assets);\\r\\n\\r\\n /// @notice Returns pool token proportions\\r\\n function _depositorPoolWeights() internal virtual view returns (uint[] memory weights, uint total);\\r\\n\\r\\n /// @notice Returns pool token reserves\\r\\n function _depositorPoolReserves() internal virtual view returns (uint[] memory reserves);\\r\\n\\r\\n /// @notice Returns depositor's pool shares / lp token amount\\r\\n function _depositorLiquidity() internal virtual view returns (uint);\\r\\n\\r\\n //// @notice Total amount of LP tokens in the depositor\\r\\n function _depositorTotalSupply() internal view virtual returns (uint);\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n /// @dev Depositor must care about tokens approval by itself.\\r\\n function _depositorEnter(uint[] memory amountsDesired_) internal virtual returns (\\r\\n uint[] memory amountsConsumed,\\r\\n uint liquidityOut\\r\\n );\\r\\n\\r\\n /// @notice Withdraw given lp amount from the pool.\\r\\n /// @param liquidityAmount Amount of liquidity to be converted\\r\\n /// If requested liquidityAmount >= invested, then should make full exit.\\r\\n /// @param emergency Emergency exit (only withdraw, don't claim any rewards or make any other additional actions)\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorExit(uint liquidityAmount, bool emergency) internal virtual returns (uint[] memory amountsOut);\\r\\n\\r\\n /// @notice Quotes output for given lp amount from the pool.\\r\\n /// @dev Write function with read-only behavior. BalanceR's depositor requires not-view.\\r\\n /// @param liquidityAmount Amount of liquidity to be converted\\r\\n /// If requested liquidityAmount >= invested, then should make full exit.\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorQuoteExit(uint liquidityAmount) internal virtual returns (uint[] memory amountsOut);\\r\\n\\r\\n /// @dev If pool supports emergency withdraw need to call it for emergencyExit()\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorEmergencyExit() internal virtual returns (uint[] memory amountsOut) {\\r\\n uint liquidity = _depositorLiquidity();\\r\\n return liquidity == 0\\r\\n ? new uint[](_depositorPoolAssets().length)\\r\\n : _depositorExit(liquidity, true);\\r\\n }\\r\\n\\r\\n /// @notice Claim all possible rewards.\\r\\n /// @return rewardTokens Claimed token addresses\\r\\n /// @return rewardAmounts Claimed token amounts\\r\\n /// @return depositorBalancesBefore Must have the same length as _depositorPoolAssets and represent balances before claim in the same order\\r\\n function _depositorClaimRewards() internal virtual returns (\\r\\n address[] memory rewardTokens,\\r\\n uint[] memory rewardAmounts,\\r\\n uint[] memory depositorBalancesBefore\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0xf268ae50022f5028f4717d1e0256447ce5f0c3f671080d400a436f19d182e57e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../ConverterStrategyBase.sol\\\";\\r\\nimport \\\"./UniswapV3Depositor.sol\\\";\\r\\nimport \\\"./UniswapV3ConverterStrategyLogicLib.sol\\\";\\r\\nimport \\\"../../libs/AppPlatforms.sol\\\";\\r\\nimport \\\"../../interfaces/IRebalancingV2Strategy.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\n/// @title Delta-neutral liquidity hedging converter fill-up/swap rebalancing strategy for UniswapV3\\r\\n/// @notice This strategy provides delta-neutral liquidity hedging for Uniswap V3 pools. It rebalances the liquidity\\r\\n/// by utilizing fill-up and swap methods depending on the range size of the liquidity provided.\\r\\n/// @author a17\\r\\ncontract UniswapV3ConverterStrategy is UniswapV3Depositor, ConverterStrategyBase, IRebalancingV2Strategy {\\r\\n\\r\\n //region ------------------------------------------------- Constants\\r\\n\\r\\n string public constant override NAME = \\\"UniswapV3 Converter Strategy\\\";\\r\\n string public constant override PLATFORM = AppPlatforms.UNIV3;\\r\\n string public constant override STRATEGY_VERSION = \\\"3.1.5\\\";\\r\\n\\r\\n //endregion ------------------------------------------------- Constants\\r\\n\\r\\n //region ------------------------------------------------- INIT\\r\\n\\r\\n /// @notice Initialize the strategy with the given parameters.\\r\\n /// @param controller_ The address of the controller.\\r\\n /// @param splitter_ The address of the splitter.\\r\\n /// @param converter_ The address of the converter.\\r\\n /// @param pool_ The address of the pool.\\r\\n /// @param tickRange_ The tick range for the liquidity position.\\r\\n /// @param rebalanceTickRange_ The tick range for rebalancing.\\r\\n /// @param fuseThresholds Price thresholds for tokens [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function init(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address converter_,\\r\\n address pool_,\\r\\n int24 tickRange_,\\r\\n int24 rebalanceTickRange_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external initializer {\\r\\n __ConverterStrategyBase_init(controller_, splitter_, converter_);\\r\\n UniswapV3ConverterStrategyLogicLib.initStrategyState(\\r\\n state,\\r\\n controller_,\\r\\n pool_,\\r\\n tickRange_,\\r\\n rebalanceTickRange_,\\r\\n ISplitter(splitter_).asset(),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n // setup specific name for UI\\r\\n StrategyLib2._changeStrategySpecificName(baseState, UniswapV3ConverterStrategyLogicLib.createSpecificName(state.pair));\\r\\n }\\r\\n //endregion ------------------------------------------------- INIT\\r\\n\\r\\n //region --------------------------------------------- OPERATOR ACTIONS\\r\\n\\r\\n /// @notice Manually set status of the fuse\\r\\n /// @param status See PairBasedStrategyLib.FuseStatus enum for possible values\\r\\n function setFuseStatus(uint status) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n PairBasedStrategyLib.setFuseStatus(state.pair.fuseAB, PairBasedStrategyLib.FuseStatus(status));\\r\\n }\\r\\n\\r\\n /// @notice Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// Decimals 18. The thresholds are compared with prices from TetuConverter's price oracle.\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n /// @param values Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function setFuseThresholds(uint[4] memory values) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n PairBasedStrategyLib.setFuseThresholds(state.pair.fuseAB, values);\\r\\n }\\r\\n\\r\\n /// @dev Set a dedicated contract for rewards for properly counting.\\r\\n /// It is safe to allow change it to operator - we suppose the contract only temporally store the last rewards.\\r\\n function setStrategyProfitHolder(address strategyProfitHolder) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n state.pair.strategyProfitHolder = strategyProfitHolder;\\r\\n }\\r\\n\\r\\n /// @notice Set withdrawDone value.\\r\\n /// When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying.\\r\\n /// After completion of the conversion withdrawDone can be set to 1.\\r\\n /// So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\\r\\n /// @param done 0 - full withdraw required, 1 - full withdraw was done\\r\\n function setWithdrawDone(uint done) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n state.pair.withdrawDone = done;\\r\\n }\\r\\n //endregion --------------------------------------------- OPERATOR ACTIONS\\r\\n\\r\\n //region --------------------------------------------- METRIC VIEWS\\r\\n\\r\\n /// @notice Check if the strategy is ready for hard work.\\r\\n /// @return A boolean indicating if the strategy is ready for hard work.\\r\\n function isReadyToHardWork() override external virtual view returns (bool) {\\r\\n return !needRebalance()\\r\\n && !_isFuseTriggeredOn()\\r\\n && UniswapV3ConverterStrategyLogicLib.isReadyToHardWork(state.pair, _csbs.converter);\\r\\n }\\r\\n\\r\\n /// @notice Check if the strategy needs rebalancing.\\r\\n /// @return A boolean indicating if {rebalanceNoSwaps} should be called.\\r\\n function needRebalance() public view override returns (bool) {\\r\\n return UniswapV3ConverterStrategyLogicLib.needStrategyRebalance(state.pair, _csbs.converter);\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view override returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n return PairBasedStrategyLogicLib.getDefaultState(state.pair);\\r\\n }\\r\\n //endregion ---------------------------------------------- METRIC VIEWS\\r\\n\\r\\n //region--------------------------------------------- REBALANCE\\r\\n /// @notice Rebalance using borrow/repay only, no swaps\\r\\n /// @param checkNeedRebalance Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\\r\\n function rebalanceNoSwaps(bool checkNeedRebalance) external override {\\r\\n address _controller = controller();\\r\\n StrategyLib2.onlyOperators(_controller);\\r\\n\\r\\n (uint profitToCover, uint oldTotalAssets) = _rebalanceBefore();\\r\\n uint[] memory tokenAmounts = UniswapV3ConverterStrategyLogicLib.rebalanceNoSwaps(\\r\\n _csbs,\\r\\n state.pair,\\r\\n [address(_csbs.converter), address(AppLib._getLiquidator(_controller))],\\r\\n oldTotalAssets,\\r\\n profitToCover,\\r\\n baseState.splitter,\\r\\n checkNeedRebalance,\\r\\n liquidationThresholds\\r\\n );\\r\\n _rebalanceAfter(tokenAmounts);\\r\\n state.pair.lastRebalanceNoSwap = block.timestamp;\\r\\n }\\r\\n //endregion--------------------------------------------- REBALANCE\\r\\n\\r\\n //region --------------------------------------------- Withdraw by iterations\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n function quoteWithdrawByAgg(bytes memory planEntryData) external returns (address tokenToSwap, uint amountToSwap) {\\r\\n // restriction \\\"operator only\\\" is checked inside {initWithdrawLocal} in {quoteWithdrawStep}\\r\\n\\r\\n // estimate amounts to be withdrawn from the pool\\r\\n uint totalLiquidity = state.pair.totalLiquidity;\\r\\n uint[] memory amountsOut = (totalLiquidity == 0)\\r\\n ? new uint[](2)\\r\\n : _depositorQuoteExit(totalLiquidity);\\r\\n\\r\\n return PairBasedStrategyLogicLib.quoteWithdrawByAgg(\\r\\n state.pair,\\r\\n planEntryData,\\r\\n amountsOut,\\r\\n controller(),\\r\\n _csbs.converter,\\r\\n liquidationThresholds\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool]\\r\\n /// Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt.\\r\\n /// You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\\r\\n /// @dev All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\\r\\n /// @param tokenToSwap_ What token should be swapped to other\\r\\n /// @param aggregator_ Aggregator that should be used on next swap. 0 - use liquidator\\r\\n /// @param amountToSwap_ Amount that should be swapped. 0 - no swap\\r\\n /// @param swapData Swap rote that was prepared off-chain.\\r\\n /// @param planEntryData PLAN_XXX + additional data, see IterationPlanKinds\\r\\n /// @param entryToPool Allow to enter to the pool at the end. Use false if you are going to make several iterations.\\r\\n /// It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment\\r\\n /// 0 - not allowed, 1 - allowed, 2 - allowed only if completed\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions.\\r\\n function withdrawByAggStep(\\r\\n address tokenToSwap_,\\r\\n address aggregator_,\\r\\n uint amountToSwap_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n uint entryToPool\\r\\n ) external returns (bool completed) {\\r\\n // restriction \\\"operator only\\\" is checked inside UniswapV3ConverterStrategyLogicLib.withdrawByAggStep\\r\\n // fix price changes, exit from the pool\\r\\n (uint profitToCover, uint oldTotalAssets) = _rebalanceBefore();\\r\\n\\r\\n // check \\\"operator only\\\", make withdraw step, cover-loss, send profit to cover, prepare to enter to the pool\\r\\n uint[] memory tokenAmounts;\\r\\n\\r\\n (completed, tokenAmounts) = UniswapV3ConverterStrategyLogicLib.withdrawByAggStep(\\r\\n _csbs,\\r\\n [tokenToSwap_, aggregator_, controller(), address(_csbs.converter), baseState.splitter],\\r\\n [amountToSwap_, profitToCover, oldTotalAssets, entryToPool],\\r\\n swapData,\\r\\n planEntryData,\\r\\n state.pair,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // enter to the pool\\r\\n _rebalanceAfter(tokenAmounts);\\r\\n state.pair.lastRebalanceNoSwap = 0;\\r\\n\\r\\n if (completed && _isFuseTriggeredOn()) {\\r\\n // full withdraw was completed, we can exclude next calls of withdrawByAggStep\\r\\n state.pair.withdrawDone = 1;\\r\\n }\\r\\n\\r\\n ConverterStrategyBaseLib2.fixTooHighInvestedAssets(baseState.asset, oldTotalAssets, _csbs);\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view override returns (uint) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getPropNotUnderlying18(state.pair);\\r\\n }\\r\\n //endregion ------------------------------------ Withdraw by iterations\\r\\n\\r\\n //region--------------------------------------------- INTERNAL LOGIC\\r\\n\\r\\n function _beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint /*indexAsset_*/\\r\\n ) override internal virtual returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n require(!needRebalance(), Uni3StrategyErrors.NEED_REBALANCE);\\r\\n (uint prop0, uint prop1) = UniswapV3ConverterStrategyLogicLib.getEntryDataProportions(\\r\\n IUniswapV3Pool(state.pair.pool),\\r\\n state.pair.lowerTick,\\r\\n state.pair.upperTick,\\r\\n state.pair.depositorSwapTokens\\r\\n );\\r\\n\\r\\n // get token amounts for token A, token B\\r\\n address tokenA = state.pair.tokenA;\\r\\n tokenAmounts = PairBasedStrategyLogicLib._beforeDeposit(\\r\\n converter_,\\r\\n amount_,\\r\\n tokenA,\\r\\n state.pair.tokenB,\\r\\n prop0 * 1e18 / (prop0 + prop1),\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // take into account a possibility that tokens_ can contain [B, A]\\r\\n if (tokens_[0] != tokenA) {\\r\\n (tokenAmounts[0], tokenAmounts[1]) = (tokenAmounts[1], tokenAmounts[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards, do _processClaims() after claiming, calculate earned and lost amounts\\r\\n /// @return earned The amount of earned rewards\\r\\n /// @return lost The amount of lost rewards\\r\\n /// @return assetBalanceAfterClaim The asset balance after claiming rewards.\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Total performance fee in terms of underlying\\r\\n function _handleRewards() override internal virtual returns (\\r\\n uint earned,\\r\\n uint lost,\\r\\n uint assetBalanceAfterClaim,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n ) {\\r\\n (address[] memory rewardTokens, uint[] memory amounts) = _claim();\\r\\n address asset = baseState.asset;\\r\\n earned = UniswapV3ConverterStrategyLogicLib.calcEarned(asset, controller(), rewardTokens, amounts);\\r\\n (paidDebtToInsurance, amountPerf) = _rewardsLiquidation(rewardTokens, amounts);\\r\\n lost = 0; // hide warning\\r\\n assetBalanceAfterClaim = AppLib.balance(asset);\\r\\n }\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n /// @param amount_ The amount to be deposited.\\r\\n /// @param updateTotalAssetsBeforeInvest_ A boolean indicating if the total assets should be updated before investing.\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _depositToPool(uint amount_, bool updateTotalAssetsBeforeInvest_) override internal virtual returns (\\r\\n uint strategyLoss\\r\\n ) {\\r\\n if (_isFuseTriggeredOn()) {\\r\\n uint[] memory tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = amount_;\\r\\n emit OnDepositorEnter(tokenAmounts, tokenAmounts);\\r\\n return 0;\\r\\n } else {\\r\\n return super._depositToPool(amount_, updateTotalAssetsBeforeInvest_);\\r\\n }\\r\\n }\\r\\n\\r\\n function _beforeWithdraw(uint /*amount*/) internal view override {\\r\\n require(!needRebalance(), Uni3StrategyErrors.NEED_REBALANCE);\\r\\n }\\r\\n\\r\\n /// @notice Check need-rebalance and fuse-ON\\r\\n /// @return True if the hardwork should be skipped\\r\\n function _preHardWork(bool reInvest) internal view override returns (bool) {\\r\\n reInvest; // hide warning\\r\\n require(!needRebalance(), Uni3StrategyErrors.NEED_REBALANCE);\\r\\n require(!_isFuseTriggeredOn(), Uni3StrategyErrors.FUSE_IS_ACTIVE);\\r\\n return false;\\r\\n }\\r\\n\\r\\n /// @notice Prepare to rebalance: fix price changes, call depositor exit if totalLiquidity != 0\\r\\n function _rebalanceBefore() internal returns (uint profitToCover, uint oldTotalAssets) {\\r\\n (, profitToCover) = _fixPriceChanges(true);\\r\\n oldTotalAssets = totalAssets() - profitToCover;\\r\\n\\r\\n // withdraw all liquidity from pool\\r\\n // after disableFuse() liquidity is zero\\r\\n uint liquidity = state.pair.totalLiquidity;\\r\\n if (liquidity != 0) {\\r\\n _depositorExit(liquidity, false);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make actions after rebalance: depositor enter, update invested assets\\r\\n function _rebalanceAfter(uint[] memory tokenAmounts) internal {\\r\\n if (tokenAmounts.length == 2 && !_isFuseTriggeredOn()) {\\r\\n _depositorEnter(tokenAmounts);\\r\\n }\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n\\r\\n function _isFuseTriggeredOn() internal view returns (bool) {\\r\\n return PairBasedStrategyLib.isFuseTriggeredOn(state.pair.fuseAB.status);\\r\\n }\\r\\n //endregion--------------------------------------- INTERNAL LOGIC\\r\\n}\\r\\n\",\"keccak256\":\"0x256df422ed4f91caee46bfa811bc9429b1c718593399ac5243ad78d1a6cdcfb9\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./UniswapV3DebtLib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../../libs/AppErrors.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3ConverterStrategyLogicLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_STABLE = 300;\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE = 500;\\r\\n uint internal constant HARD_WORK_USD_FEE_THRESHOLD = 100;\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event Rebalanced(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event RebalancedDebt(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event UniV3FeesClaimed(uint fee0, uint fee1);\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n\\r\\n struct State {\\r\\n PairBasedStrategyLogicLib.PairState pair;\\r\\n // additional (specific) state\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[10] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceLocal {\\r\\n /// @notice Fuse for token A and token B\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n ITetuConverter converter;\\r\\n IUniswapV3Pool pool;\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool isStablePool;\\r\\n uint[2] liquidationThresholdsAB;\\r\\n\\r\\n bool fuseStatusChangedAB;\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB;\\r\\n\\r\\n uint poolPrice;\\r\\n uint poolPriceAdjustment;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Helpers\\r\\n\\r\\n /// @dev Gets the liquidator swap slippage based on the pool type (stable or volatile).\\r\\n /// @param pool The IUniswapV3Pool instance.\\r\\n /// @return The liquidator swap slippage percentage.\\r\\n function _getLiquidatorSwapSlippage(IUniswapV3Pool pool) internal view returns (uint) {\\r\\n return isStablePool(pool) ? LIQUIDATOR_SWAP_SLIPPAGE_STABLE : LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE;\\r\\n }\\r\\n\\r\\n /// @notice Check if the given pool is a stable pool.\\r\\n /// @param pool The Uniswap V3 pool.\\r\\n /// @return A boolean indicating if the pool is stable.\\r\\n function isStablePool(IUniswapV3Pool pool) public view returns (bool) {\\r\\n return pool.fee() == 100;\\r\\n }\\r\\n\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function initStrategyState(\\r\\n State storage state,\\r\\n address controller_,\\r\\n address pool,\\r\\n int24 tickRange,\\r\\n int24 rebalanceTickRange,\\r\\n address asset_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n require(pool != address(0), AppErrors.ZERO_ADDRESS);\\r\\n address token0 = IUniswapV3Pool(pool).token0();\\r\\n address token1 = IUniswapV3Pool(pool).token1();\\r\\n\\r\\n int24[4] memory tickData;\\r\\n {\\r\\n int24 tickSpacing = UniswapV3Lib.getTickSpacing(IUniswapV3Pool(pool).fee());\\r\\n if (tickRange != 0) {\\r\\n require(tickRange == tickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_TICK_RANGE);\\r\\n require(rebalanceTickRange == rebalanceTickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_REBALANCE_TICK_RANGE);\\r\\n }\\r\\n tickData[0] = tickSpacing;\\r\\n (tickData[1], tickData[2]) = UniswapV3DebtLib.calcTickRange(pool, tickRange, tickSpacing);\\r\\n tickData[3] = rebalanceTickRange;\\r\\n }\\r\\n\\r\\n PairBasedStrategyLogicLib.setInitialDepositorValues(\\r\\n state.pair,\\r\\n [pool, asset_, token0, token1],\\r\\n tickData,\\r\\n isStablePool(IUniswapV3Pool(pool)),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n address liquidator = IController(controller_).liquidator();\\r\\n IERC20(token0).approve(liquidator, type(uint).max);\\r\\n IERC20(token1).approve(liquidator, type(uint).max);\\r\\n }\\r\\n\\r\\n function createSpecificName(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (string memory) {\\r\\n return string(abi.encodePacked(\\r\\n \\\"UniV3 \\\",\\r\\n IERC20Metadata(pairState.tokenA).symbol(),\\r\\n \\\"/\\\",\\r\\n IERC20Metadata(pairState.tokenB).symbol(),\\r\\n \\\"-\\\",\\r\\n StringLib._toString(IUniswapV3Pool(pairState.pool).fee()))\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance.\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(IUniswapV3Pool pool, int24 lowerTick, int24 upperTick, bool depositorSwapTokens) external view returns (uint, uint) {\\r\\n return UniswapV3DebtLib.getEntryDataProportions(pool, lowerTick, upperTick, depositorSwapTokens);\\r\\n }\\r\\n //endregion ------------------------------------------------ Helpers\\r\\n\\r\\n //region ------------------------------------------------ Pool info\\r\\n /// @notice Retrieve the reserves of a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return reserves An array containing the reserve amounts of the contract owned liquidity.\\r\\n function getPoolReserves(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n uint[] memory reserves\\r\\n ) {\\r\\n reserves = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (reserves[0], reserves[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.totalLiquidity\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (reserves[0], reserves[1]) = (reserves[1], reserves[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return fee0 The fees generated for the first token in the pool.\\r\\n /// @return fee1 The fees generated for the second token in the pool.\\r\\n function getFees(PairBasedStrategyLogicLib.PairState storage pairState) public view returns (uint fee0, uint fee1) {\\r\\n UniswapV3Lib.PoolPosition memory position = UniswapV3Lib.PoolPosition(pairState.pool, pairState.lowerTick, pairState.upperTick, pairState.totalLiquidity, address(this));\\r\\n (fee0, fee1) = UniswapV3Lib.getFees(position);\\r\\n }\\r\\n\\r\\n /// @notice Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the estimated exit amounts for each token in the pool.\\r\\n function quoteExit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) public view returns (uint[] memory amountsOut) {\\r\\n amountsOut = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (amountsOut[0], amountsOut[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n liquidityAmountToExit\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Pool info\\r\\n\\r\\n //region ------------------------------------------------ Join the pool\\r\\n /// @notice Enter the pool and provide liquidity with desired token amounts.\\r\\n /// @param pool The Uniswap V3 pool to provide liquidity to.\\r\\n /// @param lowerTick The lower tick value for the pool.\\r\\n /// @param upperTick The upper tick value for the pool.\\r\\n /// @param amountsDesired_ An array containing the desired amounts of tokens to provide liquidity.\\r\\n /// @param totalLiquidity The current total liquidity in the pool.\\r\\n /// @param _depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return amountsConsumed An array containing the consumed amounts for each token in the pool.\\r\\n /// @return liquidityOut The amount of liquidity added to the pool.\\r\\n /// @return totalLiquidityNew The updated total liquidity after providing liquidity.\\r\\n function enter(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint[] memory amountsDesired_,\\r\\n uint128 totalLiquidity,\\r\\n bool _depositorSwapTokens\\r\\n ) external returns (uint[] memory amountsConsumed, uint liquidityOut, uint128 totalLiquidityNew) {\\r\\n amountsConsumed = new uint[](2);\\r\\n\\r\\n if (amountsDesired_[1] > 0) {\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsDesired_[0], amountsDesired_[1]) = (amountsDesired_[1], amountsDesired_[0]);\\r\\n }\\r\\n uint128 newLiquidity;\\r\\n (amountsConsumed[0], amountsConsumed[1], newLiquidity) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, amountsDesired_[0], amountsDesired_[1]);\\r\\n pool.mint(address(this), lowerTick, upperTick, newLiquidity, \\\"\\\");\\r\\n liquidityOut = uint(newLiquidity);\\r\\n totalLiquidityNew = totalLiquidity + newLiquidity;\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsConsumed[0], amountsConsumed[1]) = (amountsConsumed[1], amountsConsumed[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountsConsumed, liquidityOut, totalLiquidityNew);\\r\\n }\\r\\n\\r\\n //endregion ------------------------------------------------ Join the pool\\r\\n\\r\\n //region ------------------------------------------------ Exit from the pool\\r\\n /// @notice Exit the pool and collect tokens proportional to the liquidity amount to exit.\\r\\n /// @param pairState The State storage object.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the collected amounts for each token in the pool.\\r\\n function exit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) external returns (uint[] memory amountsOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n uint128 liquidity = pairState.totalLiquidity;\\r\\n bool _depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n\\r\\n require(liquidity >= liquidityAmountToExit, Uni3StrategyErrors.WRONG_LIQUIDITY);\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n (amountsOut[0], amountsOut[1]) = pool.burn(lowerTick, upperTick, liquidityAmountToExit);\\r\\n\\r\\n // all fees will be collected but not returned in amountsOut\\r\\n pool.collect(address(this), lowerTick, upperTick, type(uint128).max, type(uint128).max);\\r\\n\\r\\n pairState.totalLiquidity = liquidity - liquidityAmountToExit;\\r\\n\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Exit from the pool\\r\\n\\r\\n //region ------------------------------------------------ Claims\\r\\n /// @notice Claim rewards from the Uniswap V3 pool.\\r\\n /// @return tokensOut An array containing tokenA and tokenB.\\r\\n /// @return amountsOut An array containing the amounts of token0 and token1 claimed as rewards.\\r\\n function claimRewards(PairBasedStrategyLogicLib.PairState storage pairState) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n tokensOut = new address[](2);\\r\\n tokensOut[0] = pairState.tokenA;\\r\\n tokensOut[1] = pairState.tokenB;\\r\\n\\r\\n balancesBefore = new uint[](2);\\r\\n for (uint i; i < tokensOut.length; i++) {\\r\\n balancesBefore[i] = IERC20(tokensOut[i]).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n if (pairState.totalLiquidity > 0) {\\r\\n pool.burn(lowerTick, upperTick, 0);\\r\\n (amountsOut[0], amountsOut[1]) = pool.collect(\\r\\n address(this),\\r\\n lowerTick,\\r\\n upperTick,\\r\\n type(uint128).max,\\r\\n type(uint128).max\\r\\n );\\r\\n }\\r\\n\\r\\n emit UniV3FeesClaimed(amountsOut[0], amountsOut[1]);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n\\r\\n for (uint i; i < tokensOut.length; ++i) {\\r\\n uint b = IERC20(tokensOut[i]).balanceOf(strategyProfitHolder);\\r\\n if (b > 0) {\\r\\n IERC20(tokensOut[i]).transferFrom(strategyProfitHolder, address(this), b);\\r\\n amountsOut[i] += b;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n function isReadyToHardWork(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter) external view returns (\\r\\n bool isReady\\r\\n ) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n (uint fee0, uint fee1) = getFees(pairState);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (fee0, fee1) = (fee1, fee0);\\r\\n }\\r\\n\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n address h = pairState.strategyProfitHolder;\\r\\n\\r\\n fee0 += IERC20(tokenA).balanceOf(h);\\r\\n fee1 += IERC20(tokenB).balanceOf(h);\\r\\n\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n\\r\\n uint fee0USD = fee0 * priceA / 1e18;\\r\\n uint fee1USD = fee1 * priceB / 1e18;\\r\\n\\r\\n return fee0USD > HARD_WORK_USD_FEE_THRESHOLD || fee1USD > HARD_WORK_USD_FEE_THRESHOLD;\\r\\n }\\r\\n\\r\\n function sendFeeToProfitHolder(PairBasedStrategyLogicLib.PairState storage pairState, uint fee0, uint fee1) external {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n require(strategyProfitHolder != address (0), Uni3StrategyErrors.ZERO_PROFIT_HOLDER);\\r\\n if (pairState.depositorSwapTokens) {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee1);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee0);\\r\\n } else {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee0);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee1);\\r\\n }\\r\\n emit UniV3FeesClaimed(fee0, fee1);\\r\\n }\\r\\n\\r\\n function calcEarned(address asset, address controller, address[] memory rewardTokens, uint[] memory amounts) external view returns (uint) {\\r\\n ITetuLiquidator liquidator = ITetuLiquidator(IController(controller).liquidator());\\r\\n uint len = rewardTokens.length;\\r\\n uint earned;\\r\\n for (uint i; i < len; ++i) {\\r\\n address token = rewardTokens[i];\\r\\n if (token == asset) {\\r\\n earned += amounts[i];\\r\\n } else {\\r\\n earned += liquidator.getPrice(rewardTokens[i], asset, amounts[i]);\\r\\n }\\r\\n }\\r\\n\\r\\n return earned;\\r\\n }\\r\\n //endregion ------------------------------------------------ Claims\\r\\n\\r\\n //region ------------------------------------------------ Rebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter_) external view returns (\\r\\n bool needRebalance\\r\\n ) {\\r\\n address pool = pairState.pool;\\r\\n // poolPrice should have same decimals as a price from oracle == 18\\r\\n uint poolPriceAdjustment = PairBasedStrategyLib.getPoolPriceAdjustment(IERC20Metadata(pairState.tokenA).decimals());\\r\\n uint poolPrice = UniswapV3Lib.getPrice(pool, pairState.tokenB) * poolPriceAdjustment;\\r\\n (needRebalance, , ) = PairBasedStrategyLogicLib.needStrategyRebalance(\\r\\n pairState,\\r\\n converter_,\\r\\n UniswapV3DebtLib.getCurrentTick(IUniswapV3Pool(pool)),\\r\\n poolPrice\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make rebalance without swaps (using borrowing only).\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param totalAssets_ Current value of totalAssets()\\r\\n /// @param checkNeedRebalance_ True if the function should ensure that the rebalance is required\\r\\n /// @return tokenAmounts Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\\r\\n function rebalanceNoSwaps(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n address[2] calldata converterLiquidator,\\r\\n uint totalAssets_,\\r\\n uint profitToCover,\\r\\n address splitter,\\r\\n bool checkNeedRebalance_,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n RebalanceLocal memory v;\\r\\n _initLocalVars(v, ITetuConverter(converterLiquidator[0]), pairState, liquidityThresholds_);\\r\\n v.poolPrice = UniswapV3Lib.getPrice(address(v.pool), pairState.tokenB) * v.poolPriceAdjustment;\\r\\n bool needRebalance;\\r\\n int24 tick = UniswapV3DebtLib.getCurrentTick(v.pool);\\r\\n (needRebalance,v.fuseStatusChangedAB, v.fuseStatusAB) = PairBasedStrategyLogicLib.needStrategyRebalance(pairState, v.converter, tick, v.poolPrice);\\r\\n\\r\\n // update fuse status if necessary\\r\\n if (needRebalance) {\\r\\n // we assume here, that needRebalance is true if any fuse has changed state, see needStrategyRebalance impl\\r\\n PairBasedStrategyLogicLib.updateFuseStatus(pairState, v.fuseStatusChangedAB, v.fuseStatusAB);\\r\\n }\\r\\n\\r\\n require(!checkNeedRebalance_ || needRebalance, Uni3StrategyErrors.NO_REBALANCE_NEEDED);\\r\\n\\r\\n // rebalancing debt, setting new tick range\\r\\n if (needRebalance) {\\r\\n UniswapV3DebtLib.rebalanceNoSwaps(converterLiquidator, pairState, profitToCover, totalAssets_, splitter, v.liquidationThresholdsAB, tick);\\r\\n\\r\\n uint loss;\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(v.converter, totalAssets_, v.tokenA, v.tokenB, v.liquidationThresholdsAB);\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(csbs, splitter, loss);\\r\\n }\\r\\n emit Rebalanced(loss, profitToCover, 0);\\r\\n }\\r\\n\\r\\n return tokenAmounts;\\r\\n }\\r\\n\\r\\n /// @notice Initialize {v} by state values\\r\\n function _initLocalVars(\\r\\n RebalanceLocal memory v,\\r\\n ITetuConverter converter_,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) internal view {\\r\\n v.pool = IUniswapV3Pool(pairState.pool);\\r\\n v.fuseAB = pairState.fuseAB;\\r\\n v.converter = converter_;\\r\\n v.tokenA = pairState.tokenA;\\r\\n v.tokenB = pairState.tokenB;\\r\\n v.isStablePool = pairState.isStablePool;\\r\\n v.liquidationThresholdsAB[0] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenA]);\\r\\n v.liquidationThresholdsAB[1] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenB]);\\r\\n uint poolPriceDecimals = IERC20Metadata(v.tokenA).decimals();\\r\\n v.poolPriceAdjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n /// @notice Get proportion of not-underlying in the pool, [0...1e18]\\r\\n /// prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\\r\\n function getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage pairState) view external returns (uint) {\\r\\n // get pool proportions\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n bool depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n (int24 newLowerTick, int24 newUpperTick) = UniswapV3DebtLib._calcNewTickRange(pool, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint consumed0, uint consumed1) = UniswapV3DebtLib.getEntryDataProportions(pool, newLowerTick, newUpperTick, depositorSwapTokens);\\r\\n\\r\\n require(consumed0 + consumed1 > 0, AppErrors.ZERO_VALUE);\\r\\n return consumed1 * 1e18 / (consumed0 + consumed1);\\r\\n }\\r\\n //endregion ------------------------------------------------ Rebalance\\r\\n\\r\\n //region ------------------------------------------------ WithdrawByAgg\\r\\n /// @notice Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmountsOut Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\\r\\n function withdrawByAggStep(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint entryToPool = values_[3];\\r\\n address[2] memory tokens = [pairState.tokenA, pairState.tokenB];\\r\\n\\r\\n // Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n uint[] memory tokenAmounts;\\r\\n uint loss;\\r\\n (completed, tokenAmounts, loss) = PairBasedStrategyLogicLib.withdrawByAggStep(\\r\\n addr_,\\r\\n values_,\\r\\n swapData,\\r\\n planEntryData,\\r\\n tokens,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // cover loss\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(\\r\\n csbs,\\r\\n addr_[4],\\r\\n loss\\r\\n );\\r\\n }\\r\\n emit RebalancedDebt(loss, values_[1], 0);\\r\\n\\r\\n if (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED\\r\\n || (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED && completed)\\r\\n ) {\\r\\n // We are going to enter to the pool: update lowerTick and upperTick, initialize tokenAmountsOut\\r\\n (pairState.lowerTick, pairState.upperTick) = UniswapV3DebtLib._calcNewTickRange(\\r\\n IUniswapV3Pool(pairState.pool),\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing\\r\\n );\\r\\n tokenAmountsOut = tokenAmounts;\\r\\n }\\r\\n return (completed, tokenAmountsOut); // hide warning\\r\\n }\\r\\n //endregion ------------------------------------------------ WithdrawByAgg\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4430a5a110ff7a45e1cc8930b9ec640e7f97305de498cd5647290ee1f512fa31\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Depositor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Initializable.sol\\\";\\r\\nimport \\\"../DepositorBase.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3MintCallback.sol\\\";\\r\\nimport \\\"./UniswapV3ConverterStrategyLogicLib.sol\\\";\\r\\n\\r\\n/// @title UniswapV3Depositor\\r\\n/// @dev Abstract contract that is designed to interact with Uniswap V3 pools and manage liquidity.\\r\\n/// Inherits from IUniswapV3MintCallback, DepositorBase, and Initializable.\\r\\nabstract contract UniswapV3Depositor is IUniswapV3MintCallback, DepositorBase, Initializable {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// CONSTANTS\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @dev Version of this contract. Adjust manually on each code modification.\\r\\n string public constant UNISWAPV3_DEPOSITOR_VERSION = \\\"1.0.4\\\";\\r\\n\\r\\n uint internal constant IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_A = 0;\\r\\n uint internal constant IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_B = 1;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// VARIABLES\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @dev State variable to store the current state of the whole strategy\\r\\n UniswapV3ConverterStrategyLogicLib.State internal state;\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[100 - 60] private __gap;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// View\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @return nums Balances of [tokenA, tokenB] for profit holder\\r\\n function getSpecificState() external view returns (\\r\\n uint[] memory nums\\r\\n ) {\\r\\n address strategyProfitHolder = state.pair.strategyProfitHolder;\\r\\n nums = new uint[](2);\\r\\n nums[IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_A] = IERC20(state.pair.tokenA).balanceOf(strategyProfitHolder);\\r\\n nums[IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_B] = IERC20(state.pair.tokenB).balanceOf(strategyProfitHolder);\\r\\n }\\r\\n\\r\\n /// @notice Returns the fees for the current state.\\r\\n /// @return fee0 and fee1.\\r\\n function getFees() public view returns (uint fee0, uint fee1) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getFees(state.pair);\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool assets.\\r\\n /// @return poolAssets An array containing the addresses of the pool assets.\\r\\n function _depositorPoolAssets() override internal virtual view returns (address[] memory poolAssets) {\\r\\n poolAssets = new address[](2);\\r\\n poolAssets[0] = state.pair.tokenA;\\r\\n poolAssets[1] = state.pair.tokenB;\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool weights and the total weight.\\r\\n /// @return weights An array containing the weights of the pool assets, and totalWeight the sum of the weights.\\r\\n function _depositorPoolWeights() override internal virtual view returns (uint[] memory weights, uint totalWeight) {\\r\\n weights = new uint[](2);\\r\\n weights[0] = 1;\\r\\n weights[1] = 1;\\r\\n totalWeight = 2;\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool reserves.\\r\\n /// @return reserves An array containing the reserves of the pool assets.\\r\\n function _depositorPoolReserves() override internal virtual view returns (uint[] memory reserves) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getPoolReserves(state.pair);\\r\\n }\\r\\n\\r\\n /// @notice Returns the current liquidity of the depositor.\\r\\n /// @return The current liquidity of the depositor.\\r\\n function _depositorLiquidity() override internal virtual view returns (uint) {\\r\\n return uint(state.pair.totalLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Returns the total supply of the depositor.\\r\\n /// @return In UniV3 we can not calculate the total supply of the whole pool. Return only ourself value.\\r\\n function _depositorTotalSupply() override internal view virtual returns (uint) {\\r\\n return uint(state.pair.totalLiquidity);\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// CALLBACK\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Callback function called by Uniswap V3 pool on mint operation.\\r\\n /// @param amount0Owed The amount of token0 owed to the pool.\\r\\n /// @param amount1Owed The amount of token1 owed to the pool.\\r\\n function uniswapV3MintCallback(\\r\\n uint amount0Owed,\\r\\n uint amount1Owed,\\r\\n bytes calldata /*_data*/\\r\\n ) external override {\\r\\n require(msg.sender == state.pair.pool, Uni3StrategyErrors.NOT_CALLBACK_CALLER);\\r\\n if (amount0Owed > 0) IERC20(state.pair.depositorSwapTokens ? state.pair.tokenB : state.pair.tokenA).safeTransfer(msg.sender, amount0Owed);\\r\\n if (amount1Owed > 0) IERC20(state.pair.depositorSwapTokens ? state.pair.tokenA : state.pair.tokenB).safeTransfer(msg.sender, amount1Owed);\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// Enter, exit\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Handles the deposit operation.\\r\\n function _depositorEnter(uint[] memory amountsDesired_) override internal virtual returns (\\r\\n uint[] memory amountsConsumed,\\r\\n uint liquidityOut\\r\\n ) {\\r\\n (amountsConsumed, liquidityOut, state.pair.totalLiquidity) = UniswapV3ConverterStrategyLogicLib.enter(\\r\\n IUniswapV3Pool(state.pair.pool),\\r\\n state.pair.lowerTick,\\r\\n state.pair.upperTick,\\r\\n amountsDesired_,\\r\\n state.pair.totalLiquidity,\\r\\n state.pair.depositorSwapTokens\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Handles the withdrawal operation.\\r\\n /// @param liquidityAmount The amount of liquidity to be withdrawn.\\r\\n /// @param emergency Emergency exit (only withdraw, don't claim any rewards or make any other additional actions)\\r\\n /// @return amountsOut The amounts of the tokens withdrawn.\\r\\n function _depositorExit(uint liquidityAmount, bool emergency) override internal virtual returns (uint[] memory amountsOut) {\\r\\n uint fee0;\\r\\n uint fee1;\\r\\n if (! emergency) {\\r\\n (fee0, fee1) = getFees();\\r\\n }\\r\\n amountsOut = UniswapV3ConverterStrategyLogicLib.exit(state.pair, uint128(liquidityAmount));\\r\\n if (! emergency) {\\r\\n UniswapV3ConverterStrategyLogicLib.sendFeeToProfitHolder(state.pair, fee0, fee1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the amount of tokens that would be withdrawn based on the provided liquidity amount.\\r\\n /// @param liquidityAmount The amount of liquidity to quote the withdrawal for.\\r\\n /// @return amountsOut The amounts of the tokens that would be withdrawn, underlying is first\\r\\n function _depositorQuoteExit(uint liquidityAmount) override internal virtual returns (uint[] memory amountsOut) {\\r\\n amountsOut = UniswapV3ConverterStrategyLogicLib.quoteExit(state.pair, uint128(liquidityAmount));\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// Claim rewards\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Claims all possible rewards.\\r\\n /// @return tokensOut An array containing the addresses of the reward tokens,\\r\\n /// @return amountsOut An array containing the amounts of the reward tokens.\\r\\n function _depositorClaimRewards() override internal virtual returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n (tokensOut, amountsOut, balancesBefore) = UniswapV3ConverterStrategyLogicLib.claimRewards(state.pair);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x8820cb9102960e222a4bcc12e83e77505c6f7b97cf70670466e5d5b51b9d52a0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615c5080620000f36000396000f3fe608060405234801561001057600080fd5b50600436106103645760003560e01c806371ee0175116101c9578063b429afeb116100ff578063d3487997116100ad578063dfeb10321161007c578063dfeb103214610771578063e50df07d14610784578063f77c479114610797578063ffb86c6a1461079f57600080fd5b8063d348799714610730578063db8d55f114610743578063de3d047c1461074b578063dee1f0e41461075e57600080fd5b8063b429afeb146106b9578063b77c975b146106cc578063bd38837b146106fe578063cd4c81561461070f578063ce2f184214610720578063ceee861d1461050a578063d295ea701461072857600080fd5b806387c7f770116101775780639d0bcca0116101465780639d0bcca01461065a578063a3f4df7e14610662578063ab9e3eee1461069e578063b2457556146106a657600080fd5b806387c7f77014610610578063936725ec1461058257806396b7b14e14610623578063996a6c9c1461063657600080fd5b806371ee01751461057a57806373a50ef51461058257806378327438146105a65780637cc96380146105c65780637eba7ba6146105ce5780637efc77fa146105e0578063877887821461060857600080fd5b80634ba31b011161029e578063546799631161024c57806363e277341161021b57806363e277341461052e5780636b5fba5a146105415780636ffb4c8e146105545780637063a2371461056757600080fd5b806354679963146104e35780635641ec03146104f85780635cfc1a51146105005780636207a0cf1461050a57600080fd5b80634ba31b01146104635780634e71d92d1461046b5780634fa5d854146104735780634fac6ccd1461049057806351e03fbe146104a357806352bbbb74146104b65780635412335d146104cb57600080fd5b8063261efa12116103165780633cd8045e116102e55780633cd8045e1461042f57806342fdb471146104405780634593144c146104535780634ad0b6841461045b57600080fd5b8063261efa12146103fd578063325a19f11461040557806333c5b58e1461040d57806338d52e0f1461041557600080fd5b806301e1d1141461036957806301ffc9a714610384578063066a6fc3146103a75780630acd12c7146103ba5780630e30428d146103c25780631d2dca9e146103d75780632221eb3c146103ea575b600080fd5b6103716107a7565b6040519081526020015b60405180910390f35b61039761039236600461484f565b610832565b604051901515815260200161037b565b6103976103b5366004614954565b610878565b610371610a57565b6103d56103d03660046149ee565b610b79565b005b6103d56103e5366004614a28565b610c1d565b6103d56103f8366004614a45565b610d86565b606854610371565b610371610dfc565b610371610e2c565b6064546001600160a01b03165b60405161037b9190614a5e565b6065546001600160a01b0316610422565b6103d561044e366004614a45565b610eac565b610371610f9b565b609754610371565b610371610fcb565b6103d5611042565b61047b6110bc565b6040805192835260208301919091520161037b565b6103d561049e366004614a72565b61112a565b6103716104b1366004614a45565b61125c565b6104be611424565b60405161037b9190614aca565b6104d3611574565b60405161037b9493929190614b0f565b6104eb611603565b60405161037b9190614c03565b6103d5611698565b600160ff1b610371565b6104eb60405180604001604052806005815260200164332e312e3560d81b81525081565b6103d561053c366004614c57565b611731565b6103d561054f366004614a72565b61180f565b6103d5610562366004614a45565b6118a0565b6103d5610575366004614c8c565b611928565b609954610371565b6104eb60405180604001604052806005815260200164332e302e3160d81b81525081565b6103716105b4366004614a72565b60966020526000908152604090205481565b6103716119c6565b6103716105dc366004614a45565b5490565b6104eb60405180604001604052806009815260200168556e6973776170563360b81b81525081565b606754610371565b61037161061e3660046149ee565b6119f6565b6103d5610631366004614d4d565b611cdc565b6104eb604051806040016040528060058152602001640c4b8c0b8d60da1b81525081565b610422611d81565b6104eb6040518060400160405280601c81526020017f556e6973776170563320436f6e7665727465722053747261746567790000000081525081565b610397611db1565b6103716106b4366004614e0e565b611e5c565b6103976106c7366004614a72565b611f0b565b6106df6106da366004614e3e565b611f30565b604080516001600160a01b03909316835260208301919091520161037b565b6098546001600160a01b0316610422565b6066546001600160a01b0316610422565b609a54610371565b606954610371565b6103d561073e366004614e72565b612022565b61047b612113565b6103d5610759366004614a45565b61218b565b61039761076c366004614a72565b6121e8565b6103d561077f366004614ec4565b61226d565b6103d5610792366004614f50565b612315565b6104226125e9565b610397612619565b60006107b260975490565b6064546040516370a0823160e01b81526001600160a01b03909116906370a08231906107e2903090600401614a5e565b602060405180830381865afa1580156107ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108239190614fec565b61082d919061501b565b905090565b60006001600160e01b03198216631e94dddf60e01b148061086357506001600160e01b0319821663f73147b360e01b145b80610872575061087282612667565b92915050565b600080600061088561268c565b9150915060607353cb37197219373A95B9662D1C44ede1c554BDdD63911ec05360976040518060a001604052808e6001600160a01b03166001600160a01b031681526020018d6001600160a01b03166001600160a01b031681526020016108ea6125e9565b6001600160a01b039081168252609854811660208084019190915260655490911660409283015281516080810183528e8152908101899052808201889052606081018b905290516001600160e01b031960e086901b16815261095b939291908d908d90600190609690600401615051565b600060405180830381865af4158015610978573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a09190810190615135565b90945090506109ae816126de565b60006010558380156109c357506109c361270d565b156109ce576001600f555b606480546040516368f9467b60e01b81526001600160a01b039091166004820152602481018490526097604482015273C92346a144fa75b45b0eDAe966FEAA0E30C82c55916368f9467b910160006040518083038186803b158015610a3257600080fd5b505af4158015610a46573d6000803e3d6000fd5b505050505050509695505050505050565b606554606454604051633e53813360e11b81526000926001600160a01b0390811692169083907306c875daA1Dc2E27dd7381EB3b6be4F99553a60990637ca7026690610aa9908690869060040161517b565b602060405180830381865af4158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea9190614fec565b90506000806000610af961271f565b9250925092507306c875daA1Dc2E27dd7381EB3b6be4F99553a609639ad00ec2868686868b6040518663ffffffff1660e01b8152600401610b3e959493929190615195565b60006040518083038186803b158015610b5657600080fd5b505af4158015610b6a573d6000803e3d6000fd5b50929998505050505050505050565b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563142395ef610b9b6125e9565b6040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290851660248201526044810184905260640160006040518083038186803b158015610be957600080fd5b505af4158015610bfd573d6000803e3d6000fd5b5050506001600160a01b0390921660009081526096602052604090205550565b6000610c276125e9565b60405163124fdbb760e21b81529091507306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063493f6edc90610c61908490600401614a5e565b60006040518083038186803b158015610c7957600080fd5b505af4158015610c8d573d6000803e3d6000fd5b50505050600080610c9c61268c565b604080518082019091526098546001600160a01b0316815291935091506000907353cb37197219373A95B9662D1C44ede1c554BDdD9063b6fda8139060979060019060208101610ceb8a61273a565b6001600160a01b039081169091526065546040516001600160e01b031960e088901b168152610d2b959493928a928c929116908e906096906004016151c5565b600060405180830381865af4158015610d48573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d70919081019061523e565b9050610d7b816126de565b505042601055505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610da86125e9565b6040518263ffffffff1660e01b8152600401610dc49190614a5e565b60006040518083038186803b158015610ddc57600080fd5b505af4158015610df0573d6000803e3d6000fd5b505050600f9190915550565b600061082d6105dc60017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b615272565b60007306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610e506125e9565b6040518263ffffffff1660e01b8152600401610e6c9190614a5e565b60006040518083038186803b158015610e8457600080fd5b505af4158015610e98573d6000803e3d6000fd5b50505050610ea461279e565b509092915050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610ece6125e9565b6040518263ffffffff1660e01b8152600401610eea9190614a5e565b60006040518083038186803b158015610f0257600080fd5b505af4158015610f16573d6000803e3d6000fd5b5073E5779B35180c1048562c733A7E62f8Fe1d253C419250636bffb346915060069050836003811115610f4b57610f4b615285565b6040518363ffffffff1660e01b8152600401610f6892919061529b565b60006040518083038186803b158015610f8057600080fd5b505af4158015610f94573d6000803e3d6000fd5b5050505050565b600061082d6105dc60017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f1615272565b604051630a3c2bb160e21b8152600160048201526000907353cb37197219373A95B9662D1C44ede1c554BDdD906328f0aec490602401602060405180830381865af415801561101e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d9190614fec565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963d19cc38a6110646125e9565b6040518263ffffffff1660e01b81526004016110809190614a5e565b60006040518083038186803b15801561109857600080fd5b505af41580156110ac573d6000803e3d6000fd5b505050506110b861286f565b5050565b60655460408051808201909152600a81526914d08e8811195b9a595960b21b60208201526000918291906001600160a01b031633146111175760405162461bcd60e51b815260040161110e9190614c03565b60405180910390fd5b50611122600161292b565b915091509091565b3330146111795760405162461bcd60e51b815260206004820152601b60248201527f496e637265617365207265766973696f6e20666f7262696464656e0000000000604482015260640161110e565b60006111a96105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b6111b490600161501b565b90506111e8816111e560017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b55565b611217826111e560017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e4615272565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c8910160405180910390a15050565b606554606454604051633e53813360e11b81526000926001600160a01b0390811692169083907306c875daA1Dc2E27dd7381EB3b6be4F99553a60990637ca70266906112ae908690869060040161517b565b602060405180830381865af41580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190614fec565b90508085111561139b5760008061130e6113098489615272565b612b1d565b604051631594b05b60e01b815290985091935091507306c875daA1Dc2E27dd7381EB3b6be4F99553a60990631594b05b906113559087908790879087908c90600401615195565b602060405180830381865af4158015611372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113969190614fec565b925050505b6040516333bbb20360e11b815260048101869052602481018290526001600160a01b038084166044830152841660648201527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063677764069060840160006040518083038186803b15801561140457600080fd5b505af4158015611418573d6000803e3d6000fd5b50505050505050919050565b600280546040805183815260608082018352936001600160a01b0390931692909160208301908036833750506003546040516370a0823160e01b81529294506001600160a01b0316916370a082319150611482908490600401614a5e565b602060405180830381865afa15801561149f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c39190614fec565b826000815181106114d6576114d66152cd565b6020908102919091010152600480546040516370a0823160e01b81526001600160a01b03909116916370a082319161151091859101614a5e565b602060405180830381865afa15801561152d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115519190614fec565b82600181518110611564576115646152cd565b6020026020010181815250505090565b604051636e81b62960e01b81526001600482015260609081908190819073B2dD88095aFe40481C4969f8761DE3D6BC08D22290636e81b62990602401600060405180830381865af41580156115cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f591908101906153ab565b935093509350935090919293565b606060646006018054611615906154b5565b80601f0160208091040260200160405190810160405280929190818152602001828054611641906154b5565b801561168e5780601f106116635761010080835404028352916020019161168e565b820191906000526020600020905b81548152906001019060200180831161167157829003601f168201915b5050505050905090565b6116a0612b4e565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963bd0206826116c26125e9565b6064805460655460405160e086901b6001600160e01b03191681526001600160a01b03948516600482015291841660248301529290921660448301520160006040518083038186803b15801561171757600080fd5b505af415801561172b573d6000803e3d6000fd5b50505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc6117536125e9565b6040518263ffffffff1660e01b815260040161176f9190614a5e565b60006040518083038186803b15801561178757600080fd5b505af415801561179b573d6000803e3d6000fd5b5050604051637fc1c15b60e01b81527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099250637fc1c15b91506117db90606490869086906004016154ef565b60006040518083038186803b1580156117f357600080fd5b505af4158015611807573d6000803e3d6000fd5b505050505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc6118316125e9565b6040518263ffffffff1660e01b815260040161184d9190614a5e565b60006040518083038186803b15801561186557600080fd5b505af4158015611879573d6000803e3d6000fd5b5050600280546001600160a01b0319166001600160a01b0394909416939093179092555050565b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563d2c3cf256118c26125e9565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024810184905260440160006040518083038186803b15801561190857600080fd5b505af415801561191c573d6000803e3d6000fd5b50505060999190915550565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963ed6b63c1606485858561194f6125e9565b6040516001600160e01b031960e088901b168152600481019590955260248501939093526001600160a01b039182166044850152606484015216608482015260a40160006040518083038186803b1580156119a957600080fd5b505af41580156119bd573d6000803e3d6000fd5b50505050505050565b600061082d6105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b6000611a00614807565b611a0c84826000612b99565b805160408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611a585760405162461bcd60e51b815260040161110e9190614c03565b5060408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015283611a9e5760405162461bcd60e51b815260040161110e9190614c03565b5060001981606001511415604051806040016040528060118152602001701514cb4c4d081ddc9bdb99c8185cdcd95d607a1b81525090611af15760405162461bcd60e51b815260040161110e9190614c03565b50600080611aff6001612c13565b608085015160405163513cfdb360e11b81526001600160a01b038a16600482015260248101919091526044810183905260648181018390526084820152919350915073C92346a144fa75b45b0eDAe966FEAA0E30C82c559063a279fb669060a401602060405180830381865af4158015611b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba19190614fec565b60808401526000620186a0611bb86103e88261501b565b611bc29088615525565b611bcc919061553c565b905080846080015110611bf8578351611bf0906001600160a01b0389169088612cdd565b859450611cc9565b82600003611c3357611c0f6103e8620186a061501b565b620186a08560800151611c229190615525565b611c2c919061553c565b9450611cc9565b6000620186a0611c466103e86002615525565b611c5390620186a061501b565b611c5d9089615525565b611c67919061553c565b9050611c82856080015182611c7c9190615272565b86612d2f565b506000611c8e89612f94565b9050828111611cc257611ca66103e8620186a061501b565b611cb3620186a083615525565b611cbd919061553c565b611cc4565b875b965050505b611cd1613004565b505050505092915050565b60985460408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611d295760405162461bcd60e51b815260040161110e9190614c03565b5080518251146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090611d735760405162461bcd60e51b815260040161110e9190614c03565b50611d7c613004565b505050565b600061082d6105dc60017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e4615272565b6000611dbb612619565b158015611dcd5750611dcb61270d565b155b801561082d575060985460405163119aa29360e11b8152600160048201526001600160a01b0390911660248201527353cb37197219373A95B9662D1C44ede1c554BDdD906323354526906044015b602060405180830381865af4158015611e38573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d919061555e565b6065546064546040516001625acc3160e01b0319815260009283927306c875daA1Dc2E27dd7381EB3b6be4F99553a6099263ffa533cf92611eae926001600160a01b039182169291169060040161517b565b602060405180830381865af4158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190614fec565b90508015611f0457611f01818461301a565b91505b5092915050565b6000611f156125e9565b6001600160a01b0316826001600160a01b0316149050919050565b6005546000908190630100000090046001600160801b0316818115611f5d57611f58826130be565b611f7b565b60408051600280825260608201835290916020830190803683375050505b905073B2dD88095aFe40481C4969f8761DE3D6BC08D2226350d2e0ba60018784611fa36125e9565b6098546040516001600160e01b031960e088901b168152611fd795949392916001600160a01b03169060969060040161557b565b6040805180830381865af4158015611ff3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201791906155cc565b935093505050915091565b60015460408051808201909152601a81527f5533532d3131204e6f742063616c6c6261636b2063616c6c65720000000000006020820152906001600160a01b031633146120825760405162461bcd60e51b815260040161110e9190614c03565b5083156120d0576004546120d09033908690600160a81b900460ff166120b3576003546001600160a01b03166120c0565b6004546001600160a01b03165b6001600160a01b03169190612cdd565b821561172b5760045461172b9033908590600160a81b900460ff16612100576004546001600160a01b03166120c0565b6003546001600160a01b03169190612cdd565b604051630ba4ccab60e11b81526001600482015260009081907353cb37197219373A95B9662D1C44ede1c554BDdD906317499956906024016040805180830381865af4158015612167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112291906155fa565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a609636d51f04360646121af6125e9565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260448101849052606401610f68565b6000816001600160a01b03166121fc6125e9565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015612239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225d919061561e565b6001600160a01b03161492915050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc61228f6125e9565b6040518263ffffffff1660e01b81526004016122ab9190614a5e565b60006040518083038186803b1580156122c357600080fd5b505af41580156122d7573d6000803e3d6000fd5b5050604051630593c4c960e01b815273E5779B35180c1048562c733A7E62f8Fe1d253C419250630593c4c99150610f6890600690859060040161563b565b600054610100900460ff16158080156123355750600054600160ff909116105b8061234f5750303b15801561234f575060005460ff166001145b6123b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161110e565b6000805460ff1916600117905580156123d5576000805461ff0019166101001790555b6123e0888888613148565b7353cb37197219373A95B9662D1C44ede1c554BDdD63adc4343460018a8888888d6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612462919061561e565b896040518863ffffffff1660e01b8152600401612485979695949392919061564f565b60006040518083038186803b15801561249d57600080fd5b505af41580156124b1573d6000803e3d6000fd5b505060405163bd85be2960e01b8152600160048201527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099250637fc1c15b91506064907353cb37197219373A95B9662D1C44ede1c554BDdD9063bd85be2990602401600060405180830381865af4158015612524573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261254c91908101906156a0565b6040518363ffffffff1660e01b8152600401612569929190615716565b60006040518083038186803b15801561258157600080fd5b505af4158015612595573d6000803e3d6000fd5b5050505080156125df576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b600061082d6105dc60017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3618615272565b609854604051633934e59d60e11b8152600160048201526001600160a01b0390911660248201526000907353cb37197219373A95B9662D1C44ede1c554BDdD90637269cb3a90604401611e1b565b60006001600160e01b0319821663c19fa56160e01b14806108725750610872826131ea565b6000806126996001612c13565b92508290506126a66107a7565b6126b09190615272565b600554909150630100000090046001600160801b031680156126d9576126d781600061321f565b505b509091565b805160021480156126f457506126f261270d565b155b15612705576127028161333f565b50505b6110b8613004565b60065460009061082d9060ff16613447565b600080600061272f600019612b1d565b925092509250909192565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561277a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610872919061561e565b6064546000906060908190839081906127bf906001600160a01b0316613464565b9150915073C92346a144fa75b45b0eDAe966FEAA0E30C82c55637325f33f836127e7856134d0565b6098546040516001600160e01b031960e086901b16815261281d93929187916001600160a01b0390911690600190600401615768565b600060405180830381865af415801561283a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261286291908101906157b6565b9450945094505050909192565b606080600080600061287f61354f565b609854929550909350915073C92346a144fa75b45b0eDAe966FEAA0E30C82c559063e99de4da906001600160a01b03166128b76135da565b8686866040518663ffffffff1660e01b81526004016128da959493929190615822565b600060405180830381865af41580156128f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261291f919081019061588c565b90969095509350505050565b60008060008061293b6001612c13565b915091506129488561366e565b612a9b57600080600080600061295c613723565b94509450945094509450600061297061279e565b5050905060008060006129c38e801561298857508415155b80156129af5750609954620186a0906129a2908790615525565b6129ac919061553c565b88115b6129ba5760006129bc565b875b8b866137f6565b935093509350506129f387856129d9919061501b565b846129e4848661501b565b6129ee919061501b565b613a35565b909d509b50612a059250613a65915050565b604080518981526020810189905290810187905260608101869052608081018b905260a081018a905260c0810184905260e081018390527ff87a9dead982c86370b885093f79ded2c9a614d95d83c0c20f68e13e3b9b7d3f906101000160405180910390a1612a86612a77878c61501b565b612a81848661501b565b613a67565b9950612a92858a61501b565b98505050505050505b6098546064546040516323c1ae5960e11b815273C92346a144fa75b45b0eDAe966FEAA0E30C82c55926347835cb292612ae6926001600160a01b03928316929091169060040161517b565b60006040518083038186803b158015612afe57600080fd5b505af4158015612b12573d6000803e3d6000fd5b505050505050915091565b6000806000806000612b2f6001612c13565b91509150612b3e868284613a81565b5091989097509095509350505050565b6000612b58613c8e565b90507f768a28cb3459382a3d2173feb2dad0235f8de680b109872da581a3aa269fe5f481604051612b899190614aca565b60405180910390a16110b8613004565b612ba16135da565b604083018190526001600160a01b038085166020850152609854168352612bc89084613d15565b6060830152612bd683612f94565b608083015280612c00576040820151606454612bfb91906001600160a01b0316613d15565b612c06565b81606001515b60a0909201919091525050565b6000808215612cd0576064546000908190612c36906001600160a01b0316613464565b9150915073C92346a144fa75b45b0eDAe966FEAA0E30C82c55633643611860976064612c61866134d0565b86866040518663ffffffff1660e01b8152600401612c839594939291906158e5565b6040805180830381865af4158015612c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc391906155fa565b9094509250612cd8915050565b505060975460005b915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d7c908490613d73565b600080612d4c6005546001600160801b0363010000009091041690565b90506000612d59826130be565b9050600073C92346a144fa75b45b0eDAe966FEAA0E30C82c55630252e2c78787604001518860600151896000015187898c60a001516040518863ffffffff1660e01b8152600401612db09796959493929190615929565b602060405180830381865af4158015612dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df19190614fec565b90508015612e63576000612e0682600061321f565b600554909150630100000090046001600160801b0316612e269085615272565b91507faebc771af58936b05e89b0be7d3f9761480181abcd4a649fbdd01753fda169708282604051612e59929190615981565b60405180910390a1505b6000730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab163c432aee1876040015188606001518960000151612e9e612e996125e9565b61273a565b6000198d14612ebc578c8c60800151612eb7919061501b565b612ebe565b8c5b60966040518763ffffffff1660e01b8152600401612ee19695949392919061599a565b602060405180830381865af4158015612efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f229190614fec565b905085608001518110156040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b81525090612f795760405162461bcd60e51b815260040161110e9190614c03565b506080860151612f899082615272565b979650505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190612fc3903090600401614a5e565b602060405180830381865afa158015612fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614fec565b600061300e61279e565b50506097819055919050565b600061302461270d565b156130ad57604080516002808252606082018352600092602083019080368337019050509050838160008151811061305e5761305e6152cd565b6020026020010181815250507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d05818260405161309b9291906159dd565b60405180910390a16000915050610872565b6130b78383613e45565b9050610872565b60405163a7aced0960e01b8152600160048201526001600160801b03821660248201526060907353cb37197219373A95B9662D1C44ede1c554BDdD9063a7aced0990604401600060405180830381865af4158015613120573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610872919081019061523e565b600054610100900460ff1661316f5760405162461bcd60e51b815260040161110e90615a02565b6131798383613e6f565b609880546001600160a01b0319166001600160a01b0383161790556131a26064620186a061553c565b6099557fe4166dfcf23bbd3e3f764a99dc8fa740554c03c82d6019b81cf265f396f6f2fe6131d46064620186a061553c565b60405190815260200160405180910390a1505050565b60006001600160e01b0319821663b7b79fa960e01b148061087257506301ffc9a760e01b6001600160e01b0319831614610872565b60606000808361323757613231612113565b90925090505b604051633ae60bcb60e01b8152600160048201526001600160801b03861660248201527353cb37197219373A95B9662D1C44ede1c554BDdD90633ae60bcb90604401600060405180830381865af4158015613296573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132be919081019061523e565b92508361333757604051632b25a6cf60e01b81526001600482015260248101839052604481018290527353cb37197219373A95B9662D1C44ede1c554BDdD90632b25a6cf9060640160006040518083038186803b15801561331e57600080fd5b505af4158015613332573d6000803e3d6000fd5b505050505b505092915050565b60015460048054600554604051638008936760e01b81526060946000947353cb37197219373A95B9662D1C44ede1c554BDdD946380089367946133c5946001600160a01b0390941693600160c81b8304600290810b94600160e01b850490910b938c93630100000090046001600160801b031692600160a81b90910460ff169101615a4d565b600060405180830381865af41580156133e2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261340a9190810190615aa3565b600580546001600160801b0390921663010000000272ffffffffffffffffffffffffffffffff000000199092169190911790559094909350915050565b6000600182600381111561345d5761345d615285565b1192915050565b606060006134706135da565b915061347c8284613d15565b90506000198114156040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906134ca5760405162461bcd60e51b815260040161110e9190614c03565b50915091565b606060006134ee6005546001600160801b0363010000009091041690565b90508015613504576134ff816130be565b613548565b82516001600160401b0381111561351d5761351d614891565b604051908082528060200260200182016040528015613546578160200160208202803683370190505b505b9392505050565b60405163af31673360e01b815260016004820152606090819081907353cb37197219373A95B9662D1C44ede1c554BDdD9063af31673390602401600060405180830381865af41580156135a6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135ce9190810190615b09565b91959094509092509050565b6040805160028082526060808301845292602083019080368337505060035482519293506001600160a01b03169183915060009061361a5761361a6152cd565b6001600160a01b03928316602091820292909201015260045482519116908290600190811061364b5761364b6152cd565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b6000613678612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906136c45760405162461bcd60e51b815260040161110e9190614c03565b506136cd61270d565b15604051806040016040528060158152602001745533532d313420467573652069732061637469766560581b8152509061371a5760405162461bcd60e51b815260040161110e9190614c03565b50600092915050565b600080600080600080600061373661286f565b60645491935091506001600160a01b03167353cb37197219373A95B9662D1C44ede1c554BDdD6334d2ec3d8261376a6125e9565b86866040518563ffffffff1660e01b815260040161378b9493929190615b57565b602060405180830381865af41580156137a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137cc9190614fec565b97506137d88383613f18565b6000985090955093506137ea81612f94565b95505050509091929394565b6064546000908190819081906001600160a01b03168187891161381a576000613824565b613824888a615272565b90506000620186a08860976002015461383d9190615525565b613847919061553c565b82119050600061385684612f94565b6001600160a01b03851660009081526096602052604090205490915061387b90613fc3565b8a111561396a57818061388e5750898110155b156139565760655473C92346a144fa75b45b0eDAe966FEAA0E30C82c559063890ffb849086908d906001600160a01b03166138c9868f61501b565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084810184905260a4016040805180830381865af415801561392a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394e91906155fa565b50965061396a565b61396260008b8b613a81565b909a50985050505b81156139f85760008061397c86613464565b609854919350915060009061399c906001600160a01b0316878585613fdb565b90506139a781614293565b6139f45760006139b68261333f565b5090507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d0582826040516139ea9291906159dd565b60405180910390a1505b5050505b613a00613004565b9550613a0b84612f94565b9450613a25613a1a828b61501b565b886129e4888a61501b565b9850505050505093509350935093565b60008083831115613a5157613a4a8484615272565b9150613a5e565b613a5b8385615272565b90505b9250929050565b565b6000818311613a77576000613548565b6135488284615272565b60008060008060006000198814613ac557620186a0613aa26103e88261501b565b613aac898b61501b565b613ab69190615525565b613ac0919061553c565b613ac7565b875b9050613ad2816142df565b8015801590613ae057508515155b15613c8457613aed614807565b606454613b05906001600160a01b0316826001612b99565b80516020820151604051637a55caf360e01b815273C92346a144fa75b45b0eDAe966FEAA0E30C82c5592637a55caf392613b419260040161517b565b602060405180830381865af4158015613b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b829190614fec565b9450670de0b6b3a764000085613ba1613b9b8585612d2f565b8b613a67565b613bab9190615525565b613bb5919061553c565b6065546020830151608084015192985073C92346a144fa75b45b0eDAe966FEAA0E30C82c5592632ce30333926001600160a01b031691908b908d613bf7613004565b6040516001600160e01b031960e089901b1681526001600160a01b03968716600482015295909416602486015260448501929092526064840152608483015260a482015260c4016040805180830381865af4158015613c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7e91906155fa565b94509250505b5093509350935093565b60606000613cac6005546001600160801b0363010000009091041690565b90508015613cc457613cbf81600161321f565b613d0f565b613ccc6135da565b516001600160401b03811115613ce457613ce4614891565b604051908082528060200260200182016040528015613d0d578160200160208202803683370190505b505b91505090565b8151600090815b81811015613d6757836001600160a01b0316858281518110613d4057613d406152cd565b60200260200101516001600160a01b031603613d5f5791506108729050565b600101613d1c565b50600019949350505050565b6000613dc8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143339092919063ffffffff16565b805190915015611d7c5780806020019051810190613de6919061555e565b611d7c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161110e565b6000806000613e5384612c13565b91509150613e628582846137f6565b5091979650505050505050565b600054610100900460ff16613e965760405162461bcd60e51b815260040161110e90615a02565b613ec0817fd2de0374d4479f33e63ae5ed6ca772a10463dd883a90c612050b51fab619640061434a565b613ec9826143a0565b604051631797527d60e01b81526064600482018190526001600160a01b038085166024840152831660448301527306c875daA1Dc2E27dd7381EB3b6be4F99553a60991631797527d91016117db565b6000808351600014613a5e57730Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1635dcb613060646097613f4a6135da565b613f526125e9565b60968a8a6040518863ffffffff1660e01b8152600401613f789796959493929190615b95565b6040805180830381865af4158015613f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb891906155fa565b909590945092505050565b60008115613fd15781610872565b620186a092915050565b6060613fe5612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906140315760405162461bcd60e51b815260040161110e9190614c03565b5060015460048054604051630dc528a760e01b81526001600160a01b0390931691830191909152600160c81b8104600290810b6024840152600160e01b8204900b6044830152600160a81b900460ff161515606482015260009081907353cb37197219373A95B9662D1C44ede1c554BDdD90630dc528a7906084016040805180830381865af41580156140c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ec91906155fa565b6003546004549294509092506001600160a01b039081169173B2dD88095aFe40481C4969f8761DE3D6BC08D22291631c2040d5918b918b91869116614131888a61501b565b6141438a670de0b6b3a7640000615525565b61414d919061553c565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452918416604484015290921660648201526084810191909152609660a482015260c401600060405180830381865af41580156141b8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141e0919081019061523e565b9350806001600160a01b0316866000815181106141ff576141ff6152cd565b60200260200101516001600160a01b0316146142885783600181518110614228576142286152cd565b602002602001015184600081518110614243576142436152cd565b60200260200101518560008151811061425e5761425e6152cd565b6020026020010186600181518110614278576142786152cd565b6020908102919091010191909152525b505050949350505050565b8051600090815b818110156142d5578381815181106142b4576142b46152cd565b60200260200101516000036142cd575060019392505050565b60010161429a565b5060009392505050565b6142e7612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906110b85760405162461bcd60e51b815260040161110e9190614c03565b606061434284846000856145c5565b949350505050565b6143548282614695565b6110b85760405162461bcd60e51b815260206004820152601a60248201527f496e74657266616365206973206e6f7420737570706f72746564000000000000604482015260640161110e565b600054610100900460ff166143c75760405162461bcd60e51b815260040161110e90615a02565b6001600160a01b03811661440f5760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b604482015260640161110e565b614439817f4c2403fdcb3cff9b705d96bf0705858e3390412670a62c8bcba611ca7e20ab8661434a565b60006001600160a01b0316816001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015614482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144a6919061561e565b6001600160a01b0316036144ee5760405162461bcd60e51b815260206004820152600f60248201526e5a65726f20676f7665726e616e636560881b604482015260640161110e565b61451d816111e560017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3618615272565b61454c426111e560017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b615272565b61457b436111e560017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f1615272565b604080516001600160a01b0383168152426020820152438183015290517f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe2367134269181900360600190a150565b6060824710156146265760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161110e565b600080866001600160a01b031685876040516146429190615bfe565b60006040518083038185875af1925050503d806000811461467f576040519150601f19603f3d011682016040523d82523d6000602084013e614684565b606091505b5091509150612f8987838387614769565b60006001600160a01b0383166146dc5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b604482015260640161110e565b823b60008190036146f1576000915050610872565b6040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa92505050801561475b575060408051601f3d908101601f191682019092526147589181019061555e565b60015b156142d55791506108729050565b606083156147d85782516000036147d1576001600160a01b0385163b6147d15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161110e565b5081614342565b61434283838151156147ed5781518083602001fd5b8060405162461bcd60e51b815260040161110e9190614c03565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b60006020828403121561486157600080fd5b81356001600160e01b03198116811461354857600080fd5b6001600160a01b038116811461488e57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156148cf576148cf614891565b604052919050565b60006001600160401b038211156148f0576148f0614891565b50601f01601f191660200190565b600082601f83011261490f57600080fd5b813561492261491d826148d7565b6148a7565b81815284602083860101111561493757600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561496d57600080fd5b863561497881614879565b9550602087013561498881614879565b94506040870135935060608701356001600160401b03808211156149ab57600080fd5b6149b78a838b016148fe565b945060808901359150808211156149cd57600080fd5b506149da89828a016148fe565b92505060a087013590509295509295509295565b60008060408385031215614a0157600080fd5b8235614a0c81614879565b946020939093013593505050565b801515811461488e57600080fd5b600060208284031215614a3a57600080fd5b813561354881614a1a565b600060208284031215614a5757600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060208284031215614a8457600080fd5b813561354881614879565b600081518084526020808501945080840160005b83811015614abf57815187529582019590820190600101614aa3565b509495945050505050565b6020815260006135486020830184614a8f565b600081518084526020808501945080840160005b83811015614abf578151151587529582019590820190600101614af1565b6080808252855190820181905260009060209060a0840190828901845b82811015614b515781516001600160a01b031684529284019290840190600101614b2c565b5050508381038285015286518082528783019183019060005b81811015614b8957835160020b83529284019291840191600101614b6a565b50508481036040860152614b9d8188614a8f565b925050508281036060840152612f898185614add565b60005b83811015614bce578181015183820152602001614bb6565b50506000910152565b60008151808452614bef816020860160208601614bb3565b601f01601f19169290920160200192915050565b6020815260006135486020830184614bd7565b60008083601f840112614c2857600080fd5b5081356001600160401b03811115614c3f57600080fd5b602083019150836020828501011115613a5e57600080fd5b60008060208385031215614c6a57600080fd5b82356001600160401b03811115614c8057600080fd5b61291f85828601614c16565b600080600060608486031215614ca157600080fd5b833592506020840135614cb381614879565b929592945050506040919091013590565b60006001600160401b03821115614cdd57614cdd614891565b5060051b60200190565b600082601f830112614cf857600080fd5b81356020614d0861491d83614cc4565b82815260059290921b84018101918181019086841115614d2757600080fd5b8286015b84811015614d425780358352918301918301614d2b565b509695505050505050565b60008060408385031215614d6057600080fd5b82356001600160401b0380821115614d7757600080fd5b818501915085601f830112614d8b57600080fd5b81356020614d9b61491d83614cc4565b82815260059290921b84018101918181019089841115614dba57600080fd5b948201945b83861015614de1578535614dd281614879565b82529482019490820190614dbf565b96505086013592505080821115614df757600080fd5b50614e0485828601614ce7565b9150509250929050565b60008060408385031215614e2157600080fd5b823591506020830135614e3381614a1a565b809150509250929050565b600060208284031215614e5057600080fd5b81356001600160401b03811115614e6657600080fd5b611f01848285016148fe565b60008060008060608587031215614e8857600080fd5b843593506020850135925060408501356001600160401b03811115614eac57600080fd5b614eb887828801614c16565b95989497509550505050565b600060808284031215614ed657600080fd5b82601f830112614ee557600080fd5b604051608081018181106001600160401b0382111715614f0757614f07614891565b604052806080840185811115614f1c57600080fd5b845b81811015614f36578035835260209283019201614f1e565b509195945050505050565b8060020b811461488e57600080fd5b600080600080600080600061014080898b031215614f6d57600080fd5b8835614f7881614879565b97506020890135614f8881614879565b96506040890135614f9881614879565b95506060890135614fa881614879565b94506080890135614fb881614f41565b935060a0890135614fc881614f41565b92508881018a1015614fd957600080fd5b5060c08801905092959891949750929550565b600060208284031215614ffe57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087257610872615005565b8060005b600481101561172b578151845260209384019390910190600101615032565b60006101c089835260208084018a60005b60058110156150885781516001600160a01b031683529183019190830190600101615062565b5050505061509960c084018961502e565b806101408401526150ac81840188614bd7565b90508281036101608401526150c18187614bd7565b61018084019590955250506101a0015295945050505050565b600082601f8301126150eb57600080fd5b815160206150fb61491d83614cc4565b82815260059290921b8401810191818101908684111561511a57600080fd5b8286015b84811015614d42578051835291830191830161511e565b6000806040838503121561514857600080fd5b825161515381614a1a565b60208401519092506001600160401b0381111561516f57600080fd5b614e04858286016150da565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b8881526020808201899052610120820190604083018960005b60028110156152045781516001600160a01b0316835291830191908301906001016151de565b50505050608082019690965260a08101949094526001600160a01b039290921660c0840152151560e0830152610100909101529392505050565b60006020828403121561525057600080fd5b81516001600160401b0381111561526657600080fd5b611f01848285016150da565b8181038181111561087257610872615005565b634e487b7160e01b600052602160045260246000fd5b82815260408101600483106152c057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b634e487b7160e01b600052603260045260246000fd5b600082601f8301126152f457600080fd5b8151602061530461491d83614cc4565b82815260059290921b8401810191818101908684111561532357600080fd5b8286015b84811015614d4257805161533a81614879565b8352918301918301615327565b600082601f83011261535857600080fd5b8151602061536861491d83614cc4565b82815260059290921b8401810191818101908684111561538757600080fd5b8286015b84811015614d4257805161539e81614a1a565b835291830191830161538b565b600080600080608085870312156153c157600080fd5b84516001600160401b03808211156153d857600080fd5b6153e4888389016152e3565b95506020915081870151818111156153fb57600080fd5b8701601f8101891361540c57600080fd5b805161541a61491d82614cc4565b81815260059190911b8201840190848101908b83111561543957600080fd5b928501925b8284101561546057835161545181614f41565b8252928501929085019061543e565b60408b015190985094505050508082111561547a57600080fd5b615486888389016150da565b9350606087015191508082111561549c57600080fd5b506154a987828801615347565b91505092959194509250565b600181811c908216806154c957607f821691505b6020821081036154e957634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761087257610872615005565b60008261555957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561557057600080fd5b815161354881614a1a565b86815260c06020820152600061559460c0830188614bd7565b82810360408401526155a68188614a8f565b6001600160a01b0396871660608501529490951660808301525060a00152949350505050565b600080604083850312156155df57600080fd5b82516155ea81614879565b6020939093015192949293505050565b6000806040838503121561560d57600080fd5b505080516020909101519092909150565b60006020828403121561563057600080fd5b815161354881614879565b82815260a08101613548602083018461502e565b8781526001600160a01b0387811660208301528681166040830152600286810b606084015285900b60808084019190915290841660a08301526101408201908360c084013798975050505050505050565b6000602082840312156156b257600080fd5b81516001600160401b038111156156c857600080fd5b8201601f810184136156d957600080fd5b80516156e761491d826148d7565b8181528560208385010111156156fc57600080fd5b61570d826020830160208601614bb3565b95945050505050565b8281526040602082015260006143426040830184614bd7565b600081518084526020808501945080840160005b83811015614abf5781516001600160a01b031687529582019590820190600101615743565b60a08152600061577b60a083018861572f565b828103602084015261578d8188614a8f565b604084019690965250506001600160a01b03929092166060830152151560809091015292915050565b6000806000606084860312156157cb57600080fd5b8351925060208401516001600160401b03808211156157e957600080fd5b6157f5878388016150da565b9350604086015191508082111561580b57600080fd5b50615818868287016150da565b9150509250925092565b6001600160a01b038616815260a0602082018190526000906158469083018761572f565b8281036040840152615858818761572f565b9050828103606084015261586c8186614a8f565b905082810360808401526158808185614a8f565b98975050505050505050565b6000806040838503121561589f57600080fd5b82516001600160401b03808211156158b657600080fd5b6158c2868387016152e3565b935060208501519150808211156158d857600080fd5b50614e04858286016150da565b85815284602082015260a06040820152600061590460a0830186614a8f565b8281036060840152615916818661572f565b9150508260808301529695505050505050565b87815260e06020820152600061594260e083018961572f565b604083018890526001600160a01b0387166060840152828103608084015261596a8187614a8f565b60a0840195909552505060c0015295945050505050565b8281526040602082015260006143426040830184614a8f565b60c0815260006159ad60c083018961572f565b6020830197909752506001600160a01b039485166040820152929093166060830152608082015260a00152919050565b6040815260006159f06040830185614a8f565b828103602084015261570d8185614a8f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60018060a01b03871681528560020b60208201528460020b604082015260c060608201526000615a8060c0830186614a8f565b6001600160801b039490941660808301525090151560a090910152949350505050565b600080600060608486031215615ab857600080fd5b83516001600160401b03811115615ace57600080fd5b615ada868287016150da565b9350506020840151915060408401516001600160801b0381168114615afe57600080fd5b809150509250925092565b600080600060608486031215615b1e57600080fd5b83516001600160401b0380821115615b3557600080fd5b615b41878388016152e3565b945060208601519150808211156157e957600080fd5b6001600160a01b03858116825284166020820152608060408201819052600090615b839083018561572f565b8281036060840152612f898185614a8f565b87815286602082015260e060408201526000615bb460e083018861572f565b6001600160a01b03871660608401526080830186905282810360a0840152615bdc818661572f565b905082810360c0840152615bf08185614a8f565b9a9950505050505050505050565b60008251615c10818460208701614bb3565b919091019291505056fea2646970667358221220fbe1c7e89d746ab6276ed527c4dcd38d25ee9b4d83e00f536eb7bb3ebdcbb25764736f6c63430008110033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103645760003560e01c806371ee0175116101c9578063b429afeb116100ff578063d3487997116100ad578063dfeb10321161007c578063dfeb103214610771578063e50df07d14610784578063f77c479114610797578063ffb86c6a1461079f57600080fd5b8063d348799714610730578063db8d55f114610743578063de3d047c1461074b578063dee1f0e41461075e57600080fd5b8063b429afeb146106b9578063b77c975b146106cc578063bd38837b146106fe578063cd4c81561461070f578063ce2f184214610720578063ceee861d1461050a578063d295ea701461072857600080fd5b806387c7f770116101775780639d0bcca0116101465780639d0bcca01461065a578063a3f4df7e14610662578063ab9e3eee1461069e578063b2457556146106a657600080fd5b806387c7f77014610610578063936725ec1461058257806396b7b14e14610623578063996a6c9c1461063657600080fd5b806371ee01751461057a57806373a50ef51461058257806378327438146105a65780637cc96380146105c65780637eba7ba6146105ce5780637efc77fa146105e0578063877887821461060857600080fd5b80634ba31b011161029e578063546799631161024c57806363e277341161021b57806363e277341461052e5780636b5fba5a146105415780636ffb4c8e146105545780637063a2371461056757600080fd5b806354679963146104e35780635641ec03146104f85780635cfc1a51146105005780636207a0cf1461050a57600080fd5b80634ba31b01146104635780634e71d92d1461046b5780634fa5d854146104735780634fac6ccd1461049057806351e03fbe146104a357806352bbbb74146104b65780635412335d146104cb57600080fd5b8063261efa12116103165780633cd8045e116102e55780633cd8045e1461042f57806342fdb471146104405780634593144c146104535780634ad0b6841461045b57600080fd5b8063261efa12146103fd578063325a19f11461040557806333c5b58e1461040d57806338d52e0f1461041557600080fd5b806301e1d1141461036957806301ffc9a714610384578063066a6fc3146103a75780630acd12c7146103ba5780630e30428d146103c25780631d2dca9e146103d75780632221eb3c146103ea575b600080fd5b6103716107a7565b6040519081526020015b60405180910390f35b61039761039236600461484f565b610832565b604051901515815260200161037b565b6103976103b5366004614954565b610878565b610371610a57565b6103d56103d03660046149ee565b610b79565b005b6103d56103e5366004614a28565b610c1d565b6103d56103f8366004614a45565b610d86565b606854610371565b610371610dfc565b610371610e2c565b6064546001600160a01b03165b60405161037b9190614a5e565b6065546001600160a01b0316610422565b6103d561044e366004614a45565b610eac565b610371610f9b565b609754610371565b610371610fcb565b6103d5611042565b61047b6110bc565b6040805192835260208301919091520161037b565b6103d561049e366004614a72565b61112a565b6103716104b1366004614a45565b61125c565b6104be611424565b60405161037b9190614aca565b6104d3611574565b60405161037b9493929190614b0f565b6104eb611603565b60405161037b9190614c03565b6103d5611698565b600160ff1b610371565b6104eb60405180604001604052806005815260200164332e312e3560d81b81525081565b6103d561053c366004614c57565b611731565b6103d561054f366004614a72565b61180f565b6103d5610562366004614a45565b6118a0565b6103d5610575366004614c8c565b611928565b609954610371565b6104eb60405180604001604052806005815260200164332e302e3160d81b81525081565b6103716105b4366004614a72565b60966020526000908152604090205481565b6103716119c6565b6103716105dc366004614a45565b5490565b6104eb60405180604001604052806009815260200168556e6973776170563360b81b81525081565b606754610371565b61037161061e3660046149ee565b6119f6565b6103d5610631366004614d4d565b611cdc565b6104eb604051806040016040528060058152602001640c4b8c0b8d60da1b81525081565b610422611d81565b6104eb6040518060400160405280601c81526020017f556e6973776170563320436f6e7665727465722053747261746567790000000081525081565b610397611db1565b6103716106b4366004614e0e565b611e5c565b6103976106c7366004614a72565b611f0b565b6106df6106da366004614e3e565b611f30565b604080516001600160a01b03909316835260208301919091520161037b565b6098546001600160a01b0316610422565b6066546001600160a01b0316610422565b609a54610371565b606954610371565b6103d561073e366004614e72565b612022565b61047b612113565b6103d5610759366004614a45565b61218b565b61039761076c366004614a72565b6121e8565b6103d561077f366004614ec4565b61226d565b6103d5610792366004614f50565b612315565b6104226125e9565b610397612619565b60006107b260975490565b6064546040516370a0823160e01b81526001600160a01b03909116906370a08231906107e2903090600401614a5e565b602060405180830381865afa1580156107ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108239190614fec565b61082d919061501b565b905090565b60006001600160e01b03198216631e94dddf60e01b148061086357506001600160e01b0319821663f73147b360e01b145b80610872575061087282612667565b92915050565b600080600061088561268c565b91509150606073__$166cd655d2cd990700b75f7db5b5f84c53$__63911ec05360976040518060a001604052808e6001600160a01b03166001600160a01b031681526020018d6001600160a01b03166001600160a01b031681526020016108ea6125e9565b6001600160a01b039081168252609854811660208084019190915260655490911660409283015281516080810183528e8152908101899052808201889052606081018b905290516001600160e01b031960e086901b16815261095b939291908d908d90600190609690600401615051565b600060405180830381865af4158015610978573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109a09190810190615135565b90945090506109ae816126de565b60006010558380156109c357506109c361270d565b156109ce576001600f555b606480546040516368f9467b60e01b81526001600160a01b039091166004820152602481018490526097604482015273__$8f1afe7577f9ab973017c74eca19b86f3c$__916368f9467b910160006040518083038186803b158015610a3257600080fd5b505af4158015610a46573d6000803e3d6000fd5b505050505050509695505050505050565b606554606454604051633e53813360e11b81526000926001600160a01b03908116921690839073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90637ca7026690610aa9908690869060040161517b565b602060405180830381865af4158015610ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aea9190614fec565b90506000806000610af961271f565b92509250925073__$7dde4232fad0cb3c495beb9e735b7d0c63$__639ad00ec2868686868b6040518663ffffffff1660e01b8152600401610b3e959493929190615195565b60006040518083038186803b158015610b5657600080fd5b505af4158015610b6a573d6000803e3d6000fd5b50929998505050505050505050565b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63142395ef610b9b6125e9565b6040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290851660248201526044810184905260640160006040518083038186803b158015610be957600080fd5b505af4158015610bfd573d6000803e3d6000fd5b5050506001600160a01b0390921660009081526096602052604090205550565b6000610c276125e9565b60405163124fdbb760e21b815290915073__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063493f6edc90610c61908490600401614a5e565b60006040518083038186803b158015610c7957600080fd5b505af4158015610c8d573d6000803e3d6000fd5b50505050600080610c9c61268c565b604080518082019091526098546001600160a01b03168152919350915060009073__$166cd655d2cd990700b75f7db5b5f84c53$__9063b6fda8139060979060019060208101610ceb8a61273a565b6001600160a01b039081169091526065546040516001600160e01b031960e088901b168152610d2b959493928a928c929116908e906096906004016151c5565b600060405180830381865af4158015610d48573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d70919081019061523e565b9050610d7b816126de565b505042601055505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610da86125e9565b6040518263ffffffff1660e01b8152600401610dc49190614a5e565b60006040518083038186803b158015610ddc57600080fd5b505af4158015610df0573d6000803e3d6000fd5b505050600f9190915550565b600061082d6105dc60017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b615272565b600073__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610e506125e9565b6040518263ffffffff1660e01b8152600401610e6c9190614a5e565b60006040518083038186803b158015610e8457600080fd5b505af4158015610e98573d6000803e3d6000fd5b50505050610ea461279e565b509092915050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610ece6125e9565b6040518263ffffffff1660e01b8152600401610eea9190614a5e565b60006040518083038186803b158015610f0257600080fd5b505af4158015610f16573d6000803e3d6000fd5b5073__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250636bffb346915060069050836003811115610f4b57610f4b615285565b6040518363ffffffff1660e01b8152600401610f6892919061529b565b60006040518083038186803b158015610f8057600080fd5b505af4158015610f94573d6000803e3d6000fd5b5050505050565b600061082d6105dc60017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f1615272565b604051630a3c2bb160e21b81526001600482015260009073__$166cd655d2cd990700b75f7db5b5f84c53$__906328f0aec490602401602060405180830381865af415801561101e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d9190614fec565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63d19cc38a6110646125e9565b6040518263ffffffff1660e01b81526004016110809190614a5e565b60006040518083038186803b15801561109857600080fd5b505af41580156110ac573d6000803e3d6000fd5b505050506110b861286f565b5050565b60655460408051808201909152600a81526914d08e8811195b9a595960b21b60208201526000918291906001600160a01b031633146111175760405162461bcd60e51b815260040161110e9190614c03565b60405180910390fd5b50611122600161292b565b915091509091565b3330146111795760405162461bcd60e51b815260206004820152601b60248201527f496e637265617365207265766973696f6e20666f7262696464656e0000000000604482015260640161110e565b60006111a96105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b6111b490600161501b565b90506111e8816111e560017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b55565b611217826111e560017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e4615272565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c8910160405180910390a15050565b606554606454604051633e53813360e11b81526000926001600160a01b03908116921690839073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90637ca70266906112ae908690869060040161517b565b602060405180830381865af41580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190614fec565b90508085111561139b5760008061130e6113098489615272565b612b1d565b604051631594b05b60e01b8152909850919350915073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90631594b05b906113559087908790879087908c90600401615195565b602060405180830381865af4158015611372573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113969190614fec565b925050505b6040516333bbb20360e11b815260048101869052602481018290526001600160a01b0380841660448301528416606482015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063677764069060840160006040518083038186803b15801561140457600080fd5b505af4158015611418573d6000803e3d6000fd5b50505050505050919050565b600280546040805183815260608082018352936001600160a01b0390931692909160208301908036833750506003546040516370a0823160e01b81529294506001600160a01b0316916370a082319150611482908490600401614a5e565b602060405180830381865afa15801561149f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c39190614fec565b826000815181106114d6576114d66152cd565b6020908102919091010152600480546040516370a0823160e01b81526001600160a01b03909116916370a082319161151091859101614a5e565b602060405180830381865afa15801561152d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115519190614fec565b82600181518110611564576115646152cd565b6020026020010181815250505090565b604051636e81b62960e01b81526001600482015260609081908190819073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__90636e81b62990602401600060405180830381865af41580156115cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115f591908101906153ab565b935093509350935090919293565b606060646006018054611615906154b5565b80601f0160208091040260200160405190810160405280929190818152602001828054611641906154b5565b801561168e5780601f106116635761010080835404028352916020019161168e565b820191906000526020600020905b81548152906001019060200180831161167157829003601f168201915b5050505050905090565b6116a0612b4e565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63bd0206826116c26125e9565b6064805460655460405160e086901b6001600160e01b03191681526001600160a01b03948516600482015291841660248301529290921660448301520160006040518083038186803b15801561171757600080fd5b505af415801561172b573d6000803e3d6000fd5b50505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc6117536125e9565b6040518263ffffffff1660e01b815260040161176f9190614a5e565b60006040518083038186803b15801561178757600080fd5b505af415801561179b573d6000803e3d6000fd5b5050604051637fc1c15b60e01b815273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9250637fc1c15b91506117db90606490869086906004016154ef565b60006040518083038186803b1580156117f357600080fd5b505af4158015611807573d6000803e3d6000fd5b505050505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc6118316125e9565b6040518263ffffffff1660e01b815260040161184d9190614a5e565b60006040518083038186803b15801561186557600080fd5b505af4158015611879573d6000803e3d6000fd5b5050600280546001600160a01b0319166001600160a01b0394909416939093179092555050565b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63d2c3cf256118c26125e9565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024810184905260440160006040518083038186803b15801561190857600080fd5b505af415801561191c573d6000803e3d6000fd5b50505060999190915550565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63ed6b63c1606485858561194f6125e9565b6040516001600160e01b031960e088901b168152600481019590955260248501939093526001600160a01b039182166044850152606484015216608482015260a40160006040518083038186803b1580156119a957600080fd5b505af41580156119bd573d6000803e3d6000fd5b50505050505050565b600061082d6105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd615272565b6000611a00614807565b611a0c84826000612b99565b805160408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611a585760405162461bcd60e51b815260040161110e9190614c03565b5060408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015283611a9e5760405162461bcd60e51b815260040161110e9190614c03565b5060001981606001511415604051806040016040528060118152602001701514cb4c4d081ddc9bdb99c8185cdcd95d607a1b81525090611af15760405162461bcd60e51b815260040161110e9190614c03565b50600080611aff6001612c13565b608085015160405163513cfdb360e11b81526001600160a01b038a16600482015260248101919091526044810183905260648181018390526084820152919350915073__$8f1afe7577f9ab973017c74eca19b86f3c$__9063a279fb669060a401602060405180830381865af4158015611b7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba19190614fec565b60808401526000620186a0611bb86103e88261501b565b611bc29088615525565b611bcc919061553c565b905080846080015110611bf8578351611bf0906001600160a01b0389169088612cdd565b859450611cc9565b82600003611c3357611c0f6103e8620186a061501b565b620186a08560800151611c229190615525565b611c2c919061553c565b9450611cc9565b6000620186a0611c466103e86002615525565b611c5390620186a061501b565b611c5d9089615525565b611c67919061553c565b9050611c82856080015182611c7c9190615272565b86612d2f565b506000611c8e89612f94565b9050828111611cc257611ca66103e8620186a061501b565b611cb3620186a083615525565b611cbd919061553c565b611cc4565b875b965050505b611cd1613004565b505050505092915050565b60985460408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611d295760405162461bcd60e51b815260040161110e9190614c03565b5080518251146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090611d735760405162461bcd60e51b815260040161110e9190614c03565b50611d7c613004565b505050565b600061082d6105dc60017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e4615272565b6000611dbb612619565b158015611dcd5750611dcb61270d565b155b801561082d575060985460405163119aa29360e11b8152600160048201526001600160a01b03909116602482015273__$166cd655d2cd990700b75f7db5b5f84c53$__906323354526906044015b602060405180830381865af4158015611e38573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d919061555e565b6065546064546040516001625acc3160e01b03198152600092839273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9263ffa533cf92611eae926001600160a01b039182169291169060040161517b565b602060405180830381865af4158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eef9190614fec565b90508015611f0457611f01818461301a565b91505b5092915050565b6000611f156125e9565b6001600160a01b0316826001600160a01b0316149050919050565b6005546000908190630100000090046001600160801b0316818115611f5d57611f58826130be565b611f7b565b60408051600280825260608201835290916020830190803683375050505b905073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__6350d2e0ba60018784611fa36125e9565b6098546040516001600160e01b031960e088901b168152611fd795949392916001600160a01b03169060969060040161557b565b6040805180830381865af4158015611ff3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201791906155cc565b935093505050915091565b60015460408051808201909152601a81527f5533532d3131204e6f742063616c6c6261636b2063616c6c65720000000000006020820152906001600160a01b031633146120825760405162461bcd60e51b815260040161110e9190614c03565b5083156120d0576004546120d09033908690600160a81b900460ff166120b3576003546001600160a01b03166120c0565b6004546001600160a01b03165b6001600160a01b03169190612cdd565b821561172b5760045461172b9033908590600160a81b900460ff16612100576004546001600160a01b03166120c0565b6003546001600160a01b03169190612cdd565b604051630ba4ccab60e11b815260016004820152600090819073__$166cd655d2cd990700b75f7db5b5f84c53$__906317499956906024016040805180830381865af4158015612167573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112291906155fa565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__636d51f04360646121af6125e9565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260448101849052606401610f68565b6000816001600160a01b03166121fc6125e9565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015612239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225d919061561e565b6001600160a01b03161492915050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc61228f6125e9565b6040518263ffffffff1660e01b81526004016122ab9190614a5e565b60006040518083038186803b1580156122c357600080fd5b505af41580156122d7573d6000803e3d6000fd5b5050604051630593c4c960e01b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250630593c4c99150610f6890600690859060040161563b565b600054610100900460ff16158080156123355750600054600160ff909116105b8061234f5750303b15801561234f575060005460ff166001145b6123b25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161110e565b6000805460ff1916600117905580156123d5576000805461ff0019166101001790555b6123e0888888613148565b73__$166cd655d2cd990700b75f7db5b5f84c53$__63adc4343460018a8888888d6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561243e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612462919061561e565b896040518863ffffffff1660e01b8152600401612485979695949392919061564f565b60006040518083038186803b15801561249d57600080fd5b505af41580156124b1573d6000803e3d6000fd5b505060405163bd85be2960e01b81526001600482015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9250637fc1c15b915060649073__$166cd655d2cd990700b75f7db5b5f84c53$__9063bd85be2990602401600060405180830381865af4158015612524573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261254c91908101906156a0565b6040518363ffffffff1660e01b8152600401612569929190615716565b60006040518083038186803b15801561258157600080fd5b505af4158015612595573d6000803e3d6000fd5b5050505080156125df576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b600061082d6105dc60017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3618615272565b609854604051633934e59d60e11b8152600160048201526001600160a01b03909116602482015260009073__$166cd655d2cd990700b75f7db5b5f84c53$__90637269cb3a90604401611e1b565b60006001600160e01b0319821663c19fa56160e01b14806108725750610872826131ea565b6000806126996001612c13565b92508290506126a66107a7565b6126b09190615272565b600554909150630100000090046001600160801b031680156126d9576126d781600061321f565b505b509091565b805160021480156126f457506126f261270d565b155b15612705576127028161333f565b50505b6110b8613004565b60065460009061082d9060ff16613447565b600080600061272f600019612b1d565b925092509250909192565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561277a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610872919061561e565b6064546000906060908190839081906127bf906001600160a01b0316613464565b9150915073__$8f1afe7577f9ab973017c74eca19b86f3c$__637325f33f836127e7856134d0565b6098546040516001600160e01b031960e086901b16815261281d93929187916001600160a01b0390911690600190600401615768565b600060405180830381865af415801561283a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261286291908101906157b6565b9450945094505050909192565b606080600080600061287f61354f565b609854929550909350915073__$8f1afe7577f9ab973017c74eca19b86f3c$__9063e99de4da906001600160a01b03166128b76135da565b8686866040518663ffffffff1660e01b81526004016128da959493929190615822565b600060405180830381865af41580156128f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261291f919081019061588c565b90969095509350505050565b60008060008061293b6001612c13565b915091506129488561366e565b612a9b57600080600080600061295c613723565b94509450945094509450600061297061279e565b5050905060008060006129c38e801561298857508415155b80156129af5750609954620186a0906129a2908790615525565b6129ac919061553c565b88115b6129ba5760006129bc565b875b8b866137f6565b935093509350506129f387856129d9919061501b565b846129e4848661501b565b6129ee919061501b565b613a35565b909d509b50612a059250613a65915050565b604080518981526020810189905290810187905260608101869052608081018b905260a081018a905260c0810184905260e081018390527ff87a9dead982c86370b885093f79ded2c9a614d95d83c0c20f68e13e3b9b7d3f906101000160405180910390a1612a86612a77878c61501b565b612a81848661501b565b613a67565b9950612a92858a61501b565b98505050505050505b6098546064546040516323c1ae5960e11b815273__$8f1afe7577f9ab973017c74eca19b86f3c$__926347835cb292612ae6926001600160a01b03928316929091169060040161517b565b60006040518083038186803b158015612afe57600080fd5b505af4158015612b12573d6000803e3d6000fd5b505050505050915091565b6000806000806000612b2f6001612c13565b91509150612b3e868284613a81565b5091989097509095509350505050565b6000612b58613c8e565b90507f768a28cb3459382a3d2173feb2dad0235f8de680b109872da581a3aa269fe5f481604051612b899190614aca565b60405180910390a16110b8613004565b612ba16135da565b604083018190526001600160a01b038085166020850152609854168352612bc89084613d15565b6060830152612bd683612f94565b608083015280612c00576040820151606454612bfb91906001600160a01b0316613d15565b612c06565b81606001515b60a0909201919091525050565b6000808215612cd0576064546000908190612c36906001600160a01b0316613464565b9150915073__$8f1afe7577f9ab973017c74eca19b86f3c$__633643611860976064612c61866134d0565b86866040518663ffffffff1660e01b8152600401612c839594939291906158e5565b6040805180830381865af4158015612c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc391906155fa565b9094509250612cd8915050565b505060975460005b915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d7c908490613d73565b600080612d4c6005546001600160801b0363010000009091041690565b90506000612d59826130be565b9050600073__$8f1afe7577f9ab973017c74eca19b86f3c$__630252e2c78787604001518860600151896000015187898c60a001516040518863ffffffff1660e01b8152600401612db09796959493929190615929565b602060405180830381865af4158015612dcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df19190614fec565b90508015612e63576000612e0682600061321f565b600554909150630100000090046001600160801b0316612e269085615272565b91507faebc771af58936b05e89b0be7d3f9761480181abcd4a649fbdd01753fda169708282604051612e59929190615981565b60405180910390a1505b600073__$e930d50fb5f4f1298547dbcb2bb0591990$__63c432aee1876040015188606001518960000151612e9e612e996125e9565b61273a565b6000198d14612ebc578c8c60800151612eb7919061501b565b612ebe565b8c5b60966040518763ffffffff1660e01b8152600401612ee19695949392919061599a565b602060405180830381865af4158015612efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f229190614fec565b905085608001518110156040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b81525090612f795760405162461bcd60e51b815260040161110e9190614c03565b506080860151612f899082615272565b979650505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190612fc3903090600401614a5e565b602060405180830381865afa158015612fe0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108729190614fec565b600061300e61279e565b50506097819055919050565b600061302461270d565b156130ad57604080516002808252606082018352600092602083019080368337019050509050838160008151811061305e5761305e6152cd565b6020026020010181815250507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d05818260405161309b9291906159dd565b60405180910390a16000915050610872565b6130b78383613e45565b9050610872565b60405163a7aced0960e01b8152600160048201526001600160801b038216602482015260609073__$166cd655d2cd990700b75f7db5b5f84c53$__9063a7aced0990604401600060405180830381865af4158015613120573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610872919081019061523e565b600054610100900460ff1661316f5760405162461bcd60e51b815260040161110e90615a02565b6131798383613e6f565b609880546001600160a01b0319166001600160a01b0383161790556131a26064620186a061553c565b6099557fe4166dfcf23bbd3e3f764a99dc8fa740554c03c82d6019b81cf265f396f6f2fe6131d46064620186a061553c565b60405190815260200160405180910390a1505050565b60006001600160e01b0319821663b7b79fa960e01b148061087257506301ffc9a760e01b6001600160e01b0319831614610872565b60606000808361323757613231612113565b90925090505b604051633ae60bcb60e01b8152600160048201526001600160801b038616602482015273__$166cd655d2cd990700b75f7db5b5f84c53$__90633ae60bcb90604401600060405180830381865af4158015613296573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132be919081019061523e565b92508361333757604051632b25a6cf60e01b815260016004820152602481018390526044810182905273__$166cd655d2cd990700b75f7db5b5f84c53$__90632b25a6cf9060640160006040518083038186803b15801561331e57600080fd5b505af4158015613332573d6000803e3d6000fd5b505050505b505092915050565b60015460048054600554604051638008936760e01b815260609460009473__$166cd655d2cd990700b75f7db5b5f84c53$__946380089367946133c5946001600160a01b0390941693600160c81b8304600290810b94600160e01b850490910b938c93630100000090046001600160801b031692600160a81b90910460ff169101615a4d565b600060405180830381865af41580156133e2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261340a9190810190615aa3565b600580546001600160801b0390921663010000000272ffffffffffffffffffffffffffffffff000000199092169190911790559094909350915050565b6000600182600381111561345d5761345d615285565b1192915050565b606060006134706135da565b915061347c8284613d15565b90506000198114156040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906134ca5760405162461bcd60e51b815260040161110e9190614c03565b50915091565b606060006134ee6005546001600160801b0363010000009091041690565b90508015613504576134ff816130be565b613548565b82516001600160401b0381111561351d5761351d614891565b604051908082528060200260200182016040528015613546578160200160208202803683370190505b505b9392505050565b60405163af31673360e01b8152600160048201526060908190819073__$166cd655d2cd990700b75f7db5b5f84c53$__9063af31673390602401600060405180830381865af41580156135a6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135ce9190810190615b09565b91959094509092509050565b6040805160028082526060808301845292602083019080368337505060035482519293506001600160a01b03169183915060009061361a5761361a6152cd565b6001600160a01b03928316602091820292909201015260045482519116908290600190811061364b5761364b6152cd565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b6000613678612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906136c45760405162461bcd60e51b815260040161110e9190614c03565b506136cd61270d565b15604051806040016040528060158152602001745533532d313420467573652069732061637469766560581b8152509061371a5760405162461bcd60e51b815260040161110e9190614c03565b50600092915050565b600080600080600080600061373661286f565b60645491935091506001600160a01b031673__$166cd655d2cd990700b75f7db5b5f84c53$__6334d2ec3d8261376a6125e9565b86866040518563ffffffff1660e01b815260040161378b9493929190615b57565b602060405180830381865af41580156137a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137cc9190614fec565b97506137d88383613f18565b6000985090955093506137ea81612f94565b95505050509091929394565b6064546000908190819081906001600160a01b03168187891161381a576000613824565b613824888a615272565b90506000620186a08860976002015461383d9190615525565b613847919061553c565b82119050600061385684612f94565b6001600160a01b03851660009081526096602052604090205490915061387b90613fc3565b8a111561396a57818061388e5750898110155b156139565760655473__$8f1afe7577f9ab973017c74eca19b86f3c$__9063890ffb849086908d906001600160a01b03166138c9868f61501b565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084810184905260a4016040805180830381865af415801561392a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394e91906155fa565b50965061396a565b61396260008b8b613a81565b909a50985050505b81156139f85760008061397c86613464565b609854919350915060009061399c906001600160a01b0316878585613fdb565b90506139a781614293565b6139f45760006139b68261333f565b5090507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d0582826040516139ea9291906159dd565b60405180910390a1505b5050505b613a00613004565b9550613a0b84612f94565b9450613a25613a1a828b61501b565b886129e4888a61501b565b9850505050505093509350935093565b60008083831115613a5157613a4a8484615272565b9150613a5e565b613a5b8385615272565b90505b9250929050565b565b6000818311613a77576000613548565b6135488284615272565b60008060008060006000198814613ac557620186a0613aa26103e88261501b565b613aac898b61501b565b613ab69190615525565b613ac0919061553c565b613ac7565b875b9050613ad2816142df565b8015801590613ae057508515155b15613c8457613aed614807565b606454613b05906001600160a01b0316826001612b99565b80516020820151604051637a55caf360e01b815273__$8f1afe7577f9ab973017c74eca19b86f3c$__92637a55caf392613b419260040161517b565b602060405180830381865af4158015613b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b829190614fec565b9450670de0b6b3a764000085613ba1613b9b8585612d2f565b8b613a67565b613bab9190615525565b613bb5919061553c565b6065546020830151608084015192985073__$8f1afe7577f9ab973017c74eca19b86f3c$__92632ce30333926001600160a01b031691908b908d613bf7613004565b6040516001600160e01b031960e089901b1681526001600160a01b03968716600482015295909416602486015260448501929092526064840152608483015260a482015260c4016040805180830381865af4158015613c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c7e91906155fa565b94509250505b5093509350935093565b60606000613cac6005546001600160801b0363010000009091041690565b90508015613cc457613cbf81600161321f565b613d0f565b613ccc6135da565b516001600160401b03811115613ce457613ce4614891565b604051908082528060200260200182016040528015613d0d578160200160208202803683370190505b505b91505090565b8151600090815b81811015613d6757836001600160a01b0316858281518110613d4057613d406152cd565b60200260200101516001600160a01b031603613d5f5791506108729050565b600101613d1c565b50600019949350505050565b6000613dc8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143339092919063ffffffff16565b805190915015611d7c5780806020019051810190613de6919061555e565b611d7c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161110e565b6000806000613e5384612c13565b91509150613e628582846137f6565b5091979650505050505050565b600054610100900460ff16613e965760405162461bcd60e51b815260040161110e90615a02565b613ec0817fd2de0374d4479f33e63ae5ed6ca772a10463dd883a90c612050b51fab619640061434a565b613ec9826143a0565b604051631797527d60e01b81526064600482018190526001600160a01b0380851660248401528316604483015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__91631797527d91016117db565b6000808351600014613a5e5773__$e930d50fb5f4f1298547dbcb2bb0591990$__635dcb613060646097613f4a6135da565b613f526125e9565b60968a8a6040518863ffffffff1660e01b8152600401613f789796959493929190615b95565b6040805180830381865af4158015613f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb891906155fa565b909590945092505050565b60008115613fd15781610872565b620186a092915050565b6060613fe5612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906140315760405162461bcd60e51b815260040161110e9190614c03565b5060015460048054604051630dc528a760e01b81526001600160a01b0390931691830191909152600160c81b8104600290810b6024840152600160e01b8204900b6044830152600160a81b900460ff1615156064820152600090819073__$166cd655d2cd990700b75f7db5b5f84c53$__90630dc528a7906084016040805180830381865af41580156140c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ec91906155fa565b6003546004549294509092506001600160a01b039081169173__$b1ba452cecccdd06eb05ace2d0a762c7e1$__91631c2040d5918b918b91869116614131888a61501b565b6141438a670de0b6b3a7640000615525565b61414d919061553c565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452918416604484015290921660648201526084810191909152609660a482015260c401600060405180830381865af41580156141b8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141e0919081019061523e565b9350806001600160a01b0316866000815181106141ff576141ff6152cd565b60200260200101516001600160a01b0316146142885783600181518110614228576142286152cd565b602002602001015184600081518110614243576142436152cd565b60200260200101518560008151811061425e5761425e6152cd565b6020026020010186600181518110614278576142786152cd565b6020908102919091010191909152525b505050949350505050565b8051600090815b818110156142d5578381815181106142b4576142b46152cd565b60200260200101516000036142cd575060019392505050565b60010161429a565b5060009392505050565b6142e7612619565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906110b85760405162461bcd60e51b815260040161110e9190614c03565b606061434284846000856145c5565b949350505050565b6143548282614695565b6110b85760405162461bcd60e51b815260206004820152601a60248201527f496e74657266616365206973206e6f7420737570706f72746564000000000000604482015260640161110e565b600054610100900460ff166143c75760405162461bcd60e51b815260040161110e90615a02565b6001600160a01b03811661440f5760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b604482015260640161110e565b614439817f4c2403fdcb3cff9b705d96bf0705858e3390412670a62c8bcba611ca7e20ab8661434a565b60006001600160a01b0316816001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015614482573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144a6919061561e565b6001600160a01b0316036144ee5760405162461bcd60e51b815260206004820152600f60248201526e5a65726f20676f7665726e616e636560881b604482015260640161110e565b61451d816111e560017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c3618615272565b61454c426111e560017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b615272565b61457b436111e560017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f1615272565b604080516001600160a01b0383168152426020820152438183015290517f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe2367134269181900360600190a150565b6060824710156146265760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161110e565b600080866001600160a01b031685876040516146429190615bfe565b60006040518083038185875af1925050503d806000811461467f576040519150601f19603f3d011682016040523d82523d6000602084013e614684565b606091505b5091509150612f8987838387614769565b60006001600160a01b0383166146dc5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b604482015260640161110e565b823b60008190036146f1576000915050610872565b6040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa92505050801561475b575060408051601f3d908101601f191682019092526147589181019061555e565b60015b156142d55791506108729050565b606083156147d85782516000036147d1576001600160a01b0385163b6147d15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161110e565b5081614342565b61434283838151156147ed5781518083602001fd5b8060405162461bcd60e51b815260040161110e9190614c03565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b60006020828403121561486157600080fd5b81356001600160e01b03198116811461354857600080fd5b6001600160a01b038116811461488e57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156148cf576148cf614891565b604052919050565b60006001600160401b038211156148f0576148f0614891565b50601f01601f191660200190565b600082601f83011261490f57600080fd5b813561492261491d826148d7565b6148a7565b81815284602083860101111561493757600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561496d57600080fd5b863561497881614879565b9550602087013561498881614879565b94506040870135935060608701356001600160401b03808211156149ab57600080fd5b6149b78a838b016148fe565b945060808901359150808211156149cd57600080fd5b506149da89828a016148fe565b92505060a087013590509295509295509295565b60008060408385031215614a0157600080fd5b8235614a0c81614879565b946020939093013593505050565b801515811461488e57600080fd5b600060208284031215614a3a57600080fd5b813561354881614a1a565b600060208284031215614a5757600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060208284031215614a8457600080fd5b813561354881614879565b600081518084526020808501945080840160005b83811015614abf57815187529582019590820190600101614aa3565b509495945050505050565b6020815260006135486020830184614a8f565b600081518084526020808501945080840160005b83811015614abf578151151587529582019590820190600101614af1565b6080808252855190820181905260009060209060a0840190828901845b82811015614b515781516001600160a01b031684529284019290840190600101614b2c565b5050508381038285015286518082528783019183019060005b81811015614b8957835160020b83529284019291840191600101614b6a565b50508481036040860152614b9d8188614a8f565b925050508281036060840152612f898185614add565b60005b83811015614bce578181015183820152602001614bb6565b50506000910152565b60008151808452614bef816020860160208601614bb3565b601f01601f19169290920160200192915050565b6020815260006135486020830184614bd7565b60008083601f840112614c2857600080fd5b5081356001600160401b03811115614c3f57600080fd5b602083019150836020828501011115613a5e57600080fd5b60008060208385031215614c6a57600080fd5b82356001600160401b03811115614c8057600080fd5b61291f85828601614c16565b600080600060608486031215614ca157600080fd5b833592506020840135614cb381614879565b929592945050506040919091013590565b60006001600160401b03821115614cdd57614cdd614891565b5060051b60200190565b600082601f830112614cf857600080fd5b81356020614d0861491d83614cc4565b82815260059290921b84018101918181019086841115614d2757600080fd5b8286015b84811015614d425780358352918301918301614d2b565b509695505050505050565b60008060408385031215614d6057600080fd5b82356001600160401b0380821115614d7757600080fd5b818501915085601f830112614d8b57600080fd5b81356020614d9b61491d83614cc4565b82815260059290921b84018101918181019089841115614dba57600080fd5b948201945b83861015614de1578535614dd281614879565b82529482019490820190614dbf565b96505086013592505080821115614df757600080fd5b50614e0485828601614ce7565b9150509250929050565b60008060408385031215614e2157600080fd5b823591506020830135614e3381614a1a565b809150509250929050565b600060208284031215614e5057600080fd5b81356001600160401b03811115614e6657600080fd5b611f01848285016148fe565b60008060008060608587031215614e8857600080fd5b843593506020850135925060408501356001600160401b03811115614eac57600080fd5b614eb887828801614c16565b95989497509550505050565b600060808284031215614ed657600080fd5b82601f830112614ee557600080fd5b604051608081018181106001600160401b0382111715614f0757614f07614891565b604052806080840185811115614f1c57600080fd5b845b81811015614f36578035835260209283019201614f1e565b509195945050505050565b8060020b811461488e57600080fd5b600080600080600080600061014080898b031215614f6d57600080fd5b8835614f7881614879565b97506020890135614f8881614879565b96506040890135614f9881614879565b95506060890135614fa881614879565b94506080890135614fb881614f41565b935060a0890135614fc881614f41565b92508881018a1015614fd957600080fd5b5060c08801905092959891949750929550565b600060208284031215614ffe57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561087257610872615005565b8060005b600481101561172b578151845260209384019390910190600101615032565b60006101c089835260208084018a60005b60058110156150885781516001600160a01b031683529183019190830190600101615062565b5050505061509960c084018961502e565b806101408401526150ac81840188614bd7565b90508281036101608401526150c18187614bd7565b61018084019590955250506101a0015295945050505050565b600082601f8301126150eb57600080fd5b815160206150fb61491d83614cc4565b82815260059290921b8401810191818101908684111561511a57600080fd5b8286015b84811015614d42578051835291830191830161511e565b6000806040838503121561514857600080fd5b825161515381614a1a565b60208401519092506001600160401b0381111561516f57600080fd5b614e04858286016150da565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b8881526020808201899052610120820190604083018960005b60028110156152045781516001600160a01b0316835291830191908301906001016151de565b50505050608082019690965260a08101949094526001600160a01b039290921660c0840152151560e0830152610100909101529392505050565b60006020828403121561525057600080fd5b81516001600160401b0381111561526657600080fd5b611f01848285016150da565b8181038181111561087257610872615005565b634e487b7160e01b600052602160045260246000fd5b82815260408101600483106152c057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b634e487b7160e01b600052603260045260246000fd5b600082601f8301126152f457600080fd5b8151602061530461491d83614cc4565b82815260059290921b8401810191818101908684111561532357600080fd5b8286015b84811015614d4257805161533a81614879565b8352918301918301615327565b600082601f83011261535857600080fd5b8151602061536861491d83614cc4565b82815260059290921b8401810191818101908684111561538757600080fd5b8286015b84811015614d4257805161539e81614a1a565b835291830191830161538b565b600080600080608085870312156153c157600080fd5b84516001600160401b03808211156153d857600080fd5b6153e4888389016152e3565b95506020915081870151818111156153fb57600080fd5b8701601f8101891361540c57600080fd5b805161541a61491d82614cc4565b81815260059190911b8201840190848101908b83111561543957600080fd5b928501925b8284101561546057835161545181614f41565b8252928501929085019061543e565b60408b015190985094505050508082111561547a57600080fd5b615486888389016150da565b9350606087015191508082111561549c57600080fd5b506154a987828801615347565b91505092959194509250565b600181811c908216806154c957607f821691505b6020821081036154e957634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761087257610872615005565b60008261555957634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561557057600080fd5b815161354881614a1a565b86815260c06020820152600061559460c0830188614bd7565b82810360408401526155a68188614a8f565b6001600160a01b0396871660608501529490951660808301525060a00152949350505050565b600080604083850312156155df57600080fd5b82516155ea81614879565b6020939093015192949293505050565b6000806040838503121561560d57600080fd5b505080516020909101519092909150565b60006020828403121561563057600080fd5b815161354881614879565b82815260a08101613548602083018461502e565b8781526001600160a01b0387811660208301528681166040830152600286810b606084015285900b60808084019190915290841660a08301526101408201908360c084013798975050505050505050565b6000602082840312156156b257600080fd5b81516001600160401b038111156156c857600080fd5b8201601f810184136156d957600080fd5b80516156e761491d826148d7565b8181528560208385010111156156fc57600080fd5b61570d826020830160208601614bb3565b95945050505050565b8281526040602082015260006143426040830184614bd7565b600081518084526020808501945080840160005b83811015614abf5781516001600160a01b031687529582019590820190600101615743565b60a08152600061577b60a083018861572f565b828103602084015261578d8188614a8f565b604084019690965250506001600160a01b03929092166060830152151560809091015292915050565b6000806000606084860312156157cb57600080fd5b8351925060208401516001600160401b03808211156157e957600080fd5b6157f5878388016150da565b9350604086015191508082111561580b57600080fd5b50615818868287016150da565b9150509250925092565b6001600160a01b038616815260a0602082018190526000906158469083018761572f565b8281036040840152615858818761572f565b9050828103606084015261586c8186614a8f565b905082810360808401526158808185614a8f565b98975050505050505050565b6000806040838503121561589f57600080fd5b82516001600160401b03808211156158b657600080fd5b6158c2868387016152e3565b935060208501519150808211156158d857600080fd5b50614e04858286016150da565b85815284602082015260a06040820152600061590460a0830186614a8f565b8281036060840152615916818661572f565b9150508260808301529695505050505050565b87815260e06020820152600061594260e083018961572f565b604083018890526001600160a01b0387166060840152828103608084015261596a8187614a8f565b60a0840195909552505060c0015295945050505050565b8281526040602082015260006143426040830184614a8f565b60c0815260006159ad60c083018961572f565b6020830197909752506001600160a01b039485166040820152929093166060830152608082015260a00152919050565b6040815260006159f06040830185614a8f565b828103602084015261570d8185614a8f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60018060a01b03871681528560020b60208201528460020b604082015260c060608201526000615a8060c0830186614a8f565b6001600160801b039490941660808301525090151560a090910152949350505050565b600080600060608486031215615ab857600080fd5b83516001600160401b03811115615ace57600080fd5b615ada868287016150da565b9350506020840151915060408401516001600160801b0381168114615afe57600080fd5b809150509250925092565b600080600060608486031215615b1e57600080fd5b83516001600160401b0380821115615b3557600080fd5b615b41878388016152e3565b945060208601519150808211156157e957600080fd5b6001600160a01b03858116825284166020820152608060408201819052600090615b839083018561572f565b8281036060840152612f898185614a8f565b87815286602082015260e060408201526000615bb460e083018861572f565b6001600160a01b03871660608401526080830186905282810360a0840152615bdc818661572f565b905082810360c0840152615bf08185614a8f565b9a9950505050505050505050565b60008251615c10818460208701614bb3565b919091019291505056fea2646970667358221220fbe1c7e89d746ab6276ed527c4dcd38d25ee9b4d83e00f536eb7bb3ebdcbb25764736f6c63430008110033", + "numDeployments": 37, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"block\",\"type\":\"uint256\"}],\"name\":\"ContractInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"withdrawnAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorEmergencyExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"consumedAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorEnter\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"liquidityAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"withdrawnAmounts\",\"type\":\"uint256[]\"}],\"name\":\"OnDepositorExit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"investedAssetsNewPrices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedByPrices\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedHandleRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lostHandleRewards\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"earnedDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lostDeposit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paidDebtToInsurance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amountPerf\",\"type\":\"uint256\"}],\"name\":\"OnHardWorkEarnedLost\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldLogic\",\"type\":\"address\"}],\"name\":\"RevisionIncreased\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CONTROLLABLE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CONVERTER_STRATEGY_BASE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PLATFORM\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"STRATEGY_BASE_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"STRATEGY_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"UNISWAPV3_DEPOSITOR_VERSION\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"asset\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"calcInvestedAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"investedAssetsOut\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"capacity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"compoundRatio\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"converter\",\"outputs\":[{\"internalType\":\"contract ITetuConverter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"created\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createdBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"debtToInsurance\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doHardWork\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"earned\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lost\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"emergencyExit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDefaultState\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"addr\",\"type\":\"address[]\"},{\"internalType\":\"int24[]\",\"name\":\"tickData\",\"type\":\"int24[]\"},{\"internalType\":\"uint256[]\",\"name\":\"nums\",\"type\":\"uint256[]\"},{\"internalType\":\"bool[]\",\"name\":\"boolValues\",\"type\":\"bool[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"fee0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fee1\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPropNotUnderlying18\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"slot\",\"type\":\"uint256\"}],\"name\":\"getSlot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSpecificState\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"nums\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"oldLogic\",\"type\":\"address\"}],\"name\":\"increaseRevision\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"controller_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"splitter_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"converter_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool_\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickRange_\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"rebalanceTickRange_\",\"type\":\"int24\"},{\"internalType\":\"uint256[4]\",\"name\":\"fuseThresholds\",\"type\":\"uint256[4]\"}],\"name\":\"init\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"updateTotalAssetsBeforeInvest_\",\"type\":\"bool\"}],\"name\":\"investAll\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"investedAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_value\",\"type\":\"address\"}],\"name\":\"isController\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_value\",\"type\":\"address\"}],\"name\":\"isGovernance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isReadyToHardWork\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"liquidationThresholds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"needRebalance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"assets_\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts_\",\"type\":\"uint256[]\"}],\"name\":\"onTransferAmounts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceFeeRatio\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"performanceReceiver\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"planEntryData\",\"type\":\"bytes\"}],\"name\":\"quoteWithdrawByAgg\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"tokenToSwap\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amountToSwap\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"checkNeedRebalance\",\"type\":\"bool\"}],\"name\":\"rebalanceNoSwaps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reinvestThresholdPercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"theAsset_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount_\",\"type\":\"uint256\"}],\"name\":\"requirePayAmountBack\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amountOut\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"revision\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"setCompoundRatio\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"status\",\"type\":\"uint256\"}],\"name\":\"setFuseStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[4]\",\"name\":\"values\",\"type\":\"uint256[4]\"}],\"name\":\"setFuseThresholds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"setLiquidationThreshold\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"percent_\",\"type\":\"uint256\"}],\"name\":\"setReinvestThresholdPercent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"strategyProfitHolder\",\"type\":\"address\"}],\"name\":\"setStrategyProfitHolder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"setStrategySpecificName\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"done\",\"type\":\"uint256\"}],\"name\":\"setWithdrawDone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"fee_\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"ratio_\",\"type\":\"uint256\"}],\"name\":\"setupPerformanceFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"strategySpecificName\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalAssets\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0Owed\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Owed\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"uniswapV3MintCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawAllToSplitter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenToSwap_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"aggregator_\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amountToSwap_\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"swapData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"planEntryData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"entryToPool\",\"type\":\"uint256\"}],\"name\":\"withdrawByAggStep\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"completed\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawToSplitter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"strategyLoss\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"a17\",\"kind\":\"dev\",\"methods\":{\"claim()\":{\"details\":\"Manual claim rewards.\"},\"created()\":{\"returns\":{\"_0\":\"Creation timestamp\"}},\"createdBlock()\":{\"returns\":{\"_0\":\"Creation block number\"}},\"doHardWork()\":{\"returns\":{\"earned\":\"Earned amount in terms of {asset}\",\"lost\":\"Lost amount in terms of {asset}\"}},\"emergencyExit()\":{\"details\":\"In case of any issue operator can withdraw all from pool.\"},\"getDefaultState()\":{\"returns\":{\"addr\":\"[tokenA, tokenB, pool, profitHolder]\",\"boolValues\":\"[isStablePool, depositorSwapTokens]\",\"nums\":\"[totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\",\"tickData\":\"[tickSpacing, lowerTick, upperTick, rebalanceTickRange]\"}},\"getFees()\":{\"returns\":{\"fee0\":\"and fee1.\"}},\"getPropNotUnderlying18()\":{\"returns\":{\"_0\":\"Proportion of the not-underlying [0...1e18]\"}},\"getSlot(uint256)\":{\"details\":\"Gets a slot as bytes32\"},\"getSpecificState()\":{\"returns\":{\"nums\":\"Balances of [tokenA, tokenB] for profit holder\"}},\"increaseRevision(address)\":{\"details\":\"Revision should be increased on each contract upgrade\"},\"init(address,address,address,address,int24,int24,uint256[4])\":{\"params\":{\"controller_\":\"The address of the controller.\",\"converter_\":\"The address of the converter.\",\"fuseThresholds\":\"Price thresholds for tokens [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\",\"pool_\":\"The address of the pool.\",\"rebalanceTickRange_\":\"The tick range for rebalancing.\",\"splitter_\":\"The address of the splitter.\",\"tickRange_\":\"The tick range for the liquidity position.\"}},\"investAll(uint256,bool)\":{\"params\":{\"updateTotalAssetsBeforeInvest_\":\"Recalculate total assets amount before depositing. It can be false if we know exactly, that the amount is already actual.\"},\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}},\"isController(address)\":{\"details\":\"Return true if given address is controller\"},\"isReadyToHardWork()\":{\"returns\":{\"_0\":\"A boolean indicating if the strategy is ready for hard work.\"}},\"needRebalance()\":{\"returns\":{\"_0\":\"A boolean indicating if {rebalanceNoSwaps} should be called.\"}},\"onTransferAmounts(address[],uint256[])\":{\"params\":{\"amounts_\":\"Amount of {asset_} that has been sent to the user's balance\",\"assets_\":\"Any asset sent to the balance, i.e. inside repayTheBorrow\"}},\"performanceFee()\":{\"details\":\"use FEE_DENOMINATOR\"},\"previousImplementation()\":{\"details\":\"Previous logic implementation\"},\"rebalanceNoSwaps(bool)\":{\"params\":{\"checkNeedRebalance\":\"Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\"}},\"requirePayAmountBack(address,uint256)\":{\"params\":{\"amount_\":\"Required amount of {theAsset_}\",\"theAsset_\":\"Required asset (either collateral or borrow), it can be NOT underlying\"},\"returns\":{\"amountOut\":\"Amount that was send OR can be claimed on the next call. The caller should control own balance to know if the amount was actually send (because we need compatibility with exist not-NSR strategies)\"}},\"revision()\":{\"details\":\"Contract upgrade counter\"},\"setCompoundRatio(uint256)\":{\"details\":\"PlatformVoter can change compound ratio for some strategies. A strategy can implement another logic for some uniq cases.\"},\"setFuseStatus(uint256)\":{\"params\":{\"status\":\"See PairBasedStrategyLib.FuseStatus enum for possible values\"}},\"setFuseThresholds(uint256[4])\":{\"params\":{\"values\":\"Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\"}},\"setLiquidationThreshold(address,uint256)\":{\"details\":\"Liquidation thresholds are used to detect dust in many cases, not only in liquidation case\",\"params\":{\"amount\":\"Min amount of token allowed to liquidate, token's decimals are used.\"}},\"setReinvestThresholdPercent(uint256)\":{\"params\":{\"percent_\":\"New value of the percent, decimals = {REINVEST_THRESHOLD_PERCENT_DENOMINATOR}\"}},\"setStrategyProfitHolder(address)\":{\"details\":\"Set a dedicated contract for rewards for properly counting. It is safe to allow change it to operator - we suppose the contract only temporally store the last rewards.\"},\"setStrategySpecificName(string)\":{\"details\":\"The name will be used for UI.\"},\"setWithdrawDone(uint256)\":{\"params\":{\"done\":\"0 - full withdraw required, 1 - full withdraw was done\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"},\"totalAssets()\":{\"details\":\"Total amount of underlying assets under control of this strategy.\"},\"uniswapV3MintCallback(uint256,uint256,bytes)\":{\"params\":{\"amount0Owed\":\"The amount of token0 owed to the pool.\",\"amount1Owed\":\"The amount of token1 owed to the pool.\"}},\"withdrawAllToSplitter()\":{\"details\":\"Withdraws all underlying assets to the vault\",\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}},\"withdrawByAggStep(address,address,uint256,bytes,bytes,uint256)\":{\"details\":\"All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\",\"params\":{\"aggregator_\":\"Aggregator that should be used on next swap. 0 - use liquidator\",\"amountToSwap_\":\"Amount that should be swapped. 0 - no swap\",\"entryToPool\":\"Allow to enter to the pool at the end. Use false if you are going to make several iterations. It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment 0 - not allowed, 1 - allowed, 2 - allowed only if completed\",\"planEntryData\":\"PLAN_XXX + additional data, see IterationPlanKinds\",\"swapData\":\"Swap rote that was prepared off-chain.\",\"tokenToSwap_\":\"What token should be swapped to other\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to the required proportions.\"}},\"withdrawToSplitter(uint256)\":{\"details\":\"Withdraws some assets to the splitter\",\"returns\":{\"strategyLoss\":\"Loss should be covered from Insurance\"}}},\"title\":\"Delta-neutral liquidity hedging converter fill-up/swap rebalancing strategy for UniswapV3\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CONTROLLABLE_VERSION()\":{\"notice\":\"Version of the contract\"},\"capacity()\":{\"notice\":\"Unlimited capacity by default\"},\"controller()\":{\"notice\":\"Return controller address saved in the contract slot\"},\"created()\":{\"notice\":\"Return creation timestamp\"},\"createdBlock()\":{\"notice\":\"Return creation block number\"},\"doHardWork()\":{\"notice\":\"Do hard work with reinvesting\"},\"getDefaultState()\":{\"notice\":\"Returns the current state of the contract\"},\"getFees()\":{\"notice\":\"Returns the fees for the current state.\"},\"getPropNotUnderlying18()\":{\"notice\":\"Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\"},\"init(address,address,address,address,int24,int24,uint256[4])\":{\"notice\":\"Initialize the strategy with the given parameters.\"},\"investAll(uint256,bool)\":{\"notice\":\"Stakes everything the strategy holds into the reward pool. amount_ Amount transferred to the strategy balance just before calling this function\"},\"investedAssets()\":{\"notice\":\"Amount of underlying assets converted to pool assets and invested to the pool.\"},\"isGovernance(address)\":{\"notice\":\"Return true if given address is setup as governance in Controller\"},\"isReadyToHardWork()\":{\"notice\":\"Check if the strategy is ready for hard work.\"},\"liquidationThresholds(address)\":{\"notice\":\"Minimum token amounts that can be liquidated\"},\"needRebalance()\":{\"notice\":\"Check if the strategy needs rebalancing.\"},\"onTransferAmounts(address[],uint256[])\":{\"notice\":\"TetuConverter calls this function when it sends any amount to user's balance\"},\"performanceFee()\":{\"notice\":\"A percent of total profit that is sent to the {performanceReceiver} before compounding\"},\"performanceReceiver()\":{\"notice\":\"{performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\"},\"quoteWithdrawByAgg(bytes)\":{\"notice\":\"Get info about a swap required by next call of {withdrawByAggStep} within the given plan\"},\"rebalanceNoSwaps(bool)\":{\"notice\":\"Rebalance using borrow/repay only, no swaps\"},\"requirePayAmountBack(address,uint256)\":{\"notice\":\"Converters asks to send some amount back. The results depend on whether the required amount is on the balance: 1. The {amount_} exists on the balance: send the amount to TetuConverter, return {amount_} 2. The {amount_} doesn't exist on the balance. Try to receive the {amount_}. 2.1. if the required amount is received: return {amount_} 2.2. if less amount X (X < {amount_}) is received return X - gap In the case 2 no amount is send to TetuConverter. Converter should make second call of requirePayAmountBack({amountOut}) to receive the assets.\"},\"setFuseStatus(uint256)\":{\"notice\":\"Manually set status of the fuse\"},\"setFuseThresholds(uint256[4])\":{\"notice\":\"Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF] Decimals 18. The thresholds are compared with prices from TetuConverter's price oracle. Example: [0.9, 0.92, 1.08, 1.1] Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF. Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\"},\"setWithdrawDone(uint256)\":{\"notice\":\"Set withdrawDone value. When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying. After completion of the conversion withdrawDone can be set to 1. So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\"},\"setupPerformanceFee(uint256,address,uint256)\":{\"notice\":\"Set performance fee, receiver and ratio\"},\"uniswapV3MintCallback(uint256,uint256,bytes)\":{\"notice\":\"Callback function called by Uniswap V3 pool on mint operation.\"},\"withdrawByAggStep(address,address,uint256,bytes,bytes,uint256)\":{\"notice\":\"Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool] Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt. You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\"}},\"notice\":\"This strategy provides delta-neutral liquidity hedging for Uniswap V3 pools. It rebalances the liquidity by utilizing fill-up and swap methods depending on the range size of the liquidity provided.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol\":\"UniswapV3ConverterStrategy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xaeca7db2074d7c66a20c609539e1f1656e67f6981bf01f83ad6aa8aa140c8d2e\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/InterfaceIds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n/// @title Library for interface IDs\\n/// @author bogdoslav\\nlibrary InterfaceIds {\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant INTERFACE_IDS_LIB_VERSION = \\\"1.0.1\\\";\\n\\n /// default notation:\\n /// bytes4 public constant I_VOTER = type(IVoter).interfaceId;\\n\\n /// As type({Interface}).interfaceId can be changed,\\n /// when some functions changed at the interface,\\n /// so used hardcoded interface identifiers\\n\\n bytes4 public constant I_VOTER = bytes4(keccak256(\\\"IVoter\\\"));\\n bytes4 public constant I_BRIBE = bytes4(keccak256(\\\"IBribe\\\"));\\n bytes4 public constant I_GAUGE = bytes4(keccak256(\\\"IGauge\\\"));\\n bytes4 public constant I_VE_TETU = bytes4(keccak256(\\\"IVeTetu\\\"));\\n bytes4 public constant I_SPLITTER = bytes4(keccak256(\\\"ISplitter\\\"));\\n bytes4 public constant I_FORWARDER = bytes4(keccak256(\\\"IForwarder\\\"));\\n bytes4 public constant I_MULTI_POOL = bytes4(keccak256(\\\"IMultiPool\\\"));\\n bytes4 public constant I_CONTROLLER = bytes4(keccak256(\\\"IController\\\"));\\n bytes4 public constant I_TETU_ERC165 = bytes4(keccak256(\\\"ITetuERC165\\\"));\\n bytes4 public constant I_STRATEGY_V2 = bytes4(keccak256(\\\"IStrategyV2\\\"));\\n bytes4 public constant I_STRATEGY_V3 = bytes4(keccak256(\\\"IStrategyV3\\\"));\\n bytes4 public constant I_CONTROLLABLE = bytes4(keccak256(\\\"IControllable\\\"));\\n bytes4 public constant I_TETU_VAULT_V2 = bytes4(keccak256(\\\"ITetuVaultV2\\\"));\\n bytes4 public constant I_PLATFORM_VOTER = bytes4(keccak256(\\\"IPlatformVoter\\\"));\\n bytes4 public constant I_VE_DISTRIBUTOR = bytes4(keccak256(\\\"IVeDistributor\\\"));\\n bytes4 public constant I_TETU_CONVERTER = bytes4(keccak256(\\\"ITetuConverter\\\"));\\n bytes4 public constant I_VAULT_INSURANCE = bytes4(keccak256(\\\"IVaultInsurance\\\"));\\n bytes4 public constant I_STRATEGY_STRICT = bytes4(keccak256(\\\"IStrategyStrict\\\"));\\n bytes4 public constant I_ERC4626 = bytes4(keccak256(\\\"IERC4626\\\"));\\n\\n}\\n\",\"keccak256\":\"0x0b03305fffdb0ae7bca319c38ac0b43116765987cf61f529f156f46171e73de1\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/SlotsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n/// @title Library for setting / getting slot variables (used in upgradable proxy contracts)\\n/// @author bogdoslav\\nlibrary SlotsLib {\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant SLOT_LIB_VERSION = \\\"1.0.0\\\";\\n\\n // ************* GETTERS *******************\\n\\n /// @dev Gets a slot as bytes32\\n function getBytes32(bytes32 slot) internal view returns (bytes32 result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot as an address\\n function getAddress(bytes32 slot) internal view returns (address result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot as uint256\\n function getUint(bytes32 slot) internal view returns (uint result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n // ************* ARRAY GETTERS *******************\\n\\n /// @dev Gets an array length\\n function arrayLength(bytes32 slot) internal view returns (uint result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n\\n /// @dev Gets a slot array by index as address\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function addressAt(bytes32 slot, uint index) internal view returns (address result) {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n result := sload(pointer)\\n }\\n }\\n\\n /// @dev Gets a slot array by index as uint\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function uintAt(bytes32 slot, uint index) internal view returns (uint result) {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n result := sload(pointer)\\n }\\n }\\n\\n // ************* SETTERS *******************\\n\\n /// @dev Sets a slot with bytes32\\n /// @notice Check address for 0 at the setter\\n function set(bytes32 slot, bytes32 value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n /// @dev Sets a slot with address\\n /// @notice Check address for 0 at the setter\\n function set(bytes32 slot, address value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n /// @dev Sets a slot with uint\\n function set(bytes32 slot, uint value) internal {\\n assembly {\\n sstore(slot, value)\\n }\\n }\\n\\n // ************* ARRAY SETTERS *******************\\n\\n /// @dev Sets a slot array at index with address\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function setAt(bytes32 slot, uint index, address value) internal {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n sstore(pointer, value)\\n }\\n }\\n\\n /// @dev Sets a slot array at index with uint\\n /// @notice First slot is array length, elements ordered backward in memory\\n /// @notice This is unsafe, without checking array length.\\n function setAt(bytes32 slot, uint index, uint value) internal {\\n bytes32 pointer = bytes32(uint(slot) - 1 - index);\\n assembly {\\n sstore(pointer, value)\\n }\\n }\\n\\n /// @dev Sets an array length\\n function setLength(bytes32 slot, uint length) internal {\\n assembly {\\n sstore(slot, length)\\n }\\n }\\n\\n /// @dev Pushes an address to the array\\n function push(bytes32 slot, address value) internal {\\n uint length = arrayLength(slot);\\n setAt(slot, length, value);\\n setLength(slot, length + 1);\\n }\\n\\n}\\n\",\"keccak256\":\"0x883de721bbf73a85c494e45380b064b91ea2c5cd0b7a777cdacb544575761c8a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n\\nlibrary StringLib {\\n\\n /// @dev Inspired by OraclizeAPI's implementation - MIT license\\n /// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n function toString(uint value) external pure returns (string memory) {\\n return _toString(value);\\n }\\n\\n function _toString(uint value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint temp = value;\\n uint digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n function toAsciiString(address x) external pure returns (string memory) {\\n return _toAsciiString(x);\\n }\\n\\n function _toAsciiString(address x) internal pure returns (string memory) {\\n bytes memory s = new bytes(40);\\n for (uint i = 0; i < 20; i++) {\\n bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i)))));\\n bytes1 hi = bytes1(uint8(b) / 16);\\n bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));\\n s[2 * i] = _char(hi);\\n s[2 * i + 1] = _char(lo);\\n }\\n return string(s);\\n }\\n\\n function char(bytes1 b) external pure returns (bytes1 c) {\\n return _char(b);\\n }\\n\\n function _char(bytes1 b) internal pure returns (bytes1 c) {\\n if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);\\n else return bytes1(uint8(b) + 0x57);\\n }\\n\\n}\\n\",\"keccak256\":\"0xe7fef8dd3d994fd08ac32e3eff07f39546cc58dc0101f5fc7c0efebfb4f3f01a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xcaaf196e5c26fdcd072a9f0833b54cf9fbd12d08be59898f04611f685d31707a\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n * @custom:oz-retyped-from bool\\n */\\n uint8 private _initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private _initializing;\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint8 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n bool isTopLevelCall = !_initializing;\\n require(\\n (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n _initialized = 1;\\n if (isTopLevelCall) {\\n _initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n _initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint8 version) {\\n require(!_initializing && _initialized < version, \\\"Initializable: contract is already initialized\\\");\\n _initialized = version;\\n _initializing = true;\\n _;\\n _initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n require(_initializing, \\\"Initializable: contract is not initializing\\\");\\n _;\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n require(!_initializing, \\\"Initializable: contract is initializing\\\");\\n if (_initialized != type(uint8).max) {\\n _initialized = type(uint8).max;\\n emit Initialized(type(uint8).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint8) {\\n return _initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _initializing;\\n }\\n}\\n\",\"keccak256\":\"0x3c7a20b7e9d134311f43e27990f32c75ff6cb461a6136c4f83fc20734f1d82e0\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/proxy/ControllableV3.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/Initializable.sol\\\";\\nimport \\\"../tools/TetuERC165.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../lib/SlotsLib.sol\\\";\\nimport \\\"../lib/InterfaceIds.sol\\\";\\n\\n/// @title Implement basic functionality for any contract that require strict control\\n/// @dev Can be used with upgradeable pattern.\\n/// Require call __Controllable_init() in any case.\\n/// @author belbix\\nabstract contract ControllableV3 is Initializable, TetuERC165, IControllable {\\n using SlotsLib for bytes32;\\n\\n /// @notice Version of the contract\\n /// @dev Should be incremented when contract changed\\n string public constant CONTROLLABLE_VERSION = \\\"3.0.1\\\";\\n\\n bytes32 internal constant _CONTROLLER_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.controller\\\")) - 1);\\n bytes32 internal constant _CREATED_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.created\\\")) - 1);\\n bytes32 internal constant _CREATED_BLOCK_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.created_block\\\")) - 1);\\n bytes32 internal constant _REVISION_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.revision\\\")) - 1);\\n bytes32 internal constant _PREVIOUS_LOGIC_SLOT = bytes32(uint256(keccak256(\\\"eip1967.controllable.prev_logic\\\")) - 1);\\n\\n event ContractInitialized(address controller, uint ts, uint block);\\n event RevisionIncreased(uint value, address oldLogic);\\n\\n /// @dev Prevent implementation init\\n constructor() {\\n _disableInitializers();\\n }\\n\\n /// @notice Initialize contract after setup it as proxy implementation\\n /// Save block.timestamp in the \\\"created\\\" variable\\n /// @dev Use it only once after first logic setup\\n /// @param controller_ Controller address\\n function __Controllable_init(address controller_) internal onlyInitializing {\\n require(controller_ != address(0), \\\"Zero controller\\\");\\n _requireInterface(controller_, InterfaceIds.I_CONTROLLER);\\n require(IController(controller_).governance() != address(0), \\\"Zero governance\\\");\\n _CONTROLLER_SLOT.set(controller_);\\n _CREATED_SLOT.set(block.timestamp);\\n _CREATED_BLOCK_SLOT.set(block.number);\\n emit ContractInitialized(controller_, block.timestamp, block.number);\\n }\\n\\n /// @dev Return true if given address is controller\\n function isController(address _value) public override view returns (bool) {\\n return _value == controller();\\n }\\n\\n /// @notice Return true if given address is setup as governance in Controller\\n function isGovernance(address _value) public override view returns (bool) {\\n return IController(controller()).governance() == _value;\\n }\\n\\n /// @dev Contract upgrade counter\\n function revision() external view returns (uint){\\n return _REVISION_SLOT.getUint();\\n }\\n\\n /// @dev Previous logic implementation\\n function previousImplementation() external view returns (address){\\n return _PREVIOUS_LOGIC_SLOT.getAddress();\\n }\\n\\n /// @dev See {IERC165-supportsInterface}.\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_CONTROLLABLE || super.supportsInterface(interfaceId);\\n }\\n\\n // ************* SETTERS/GETTERS *******************\\n\\n /// @notice Return controller address saved in the contract slot\\n function controller() public view override returns (address) {\\n return _CONTROLLER_SLOT.getAddress();\\n }\\n\\n /// @notice Return creation timestamp\\n /// @return Creation timestamp\\n function created() external view override returns (uint256) {\\n return _CREATED_SLOT.getUint();\\n }\\n\\n /// @notice Return creation block number\\n /// @return Creation block number\\n function createdBlock() external override view returns (uint256) {\\n return _CREATED_BLOCK_SLOT.getUint();\\n }\\n\\n /// @dev Revision should be increased on each contract upgrade\\n function increaseRevision(address oldLogic) external override {\\n require(msg.sender == address(this), \\\"Increase revision forbidden\\\");\\n uint r = _REVISION_SLOT.getUint() + 1;\\n _REVISION_SLOT.set(r);\\n _PREVIOUS_LOGIC_SLOT.set(oldLogic);\\n emit RevisionIncreased(r, oldLogic);\\n }\\n\\n /// @dev Gets a slot as bytes32\\n function getSlot(uint slot) external view returns (bytes32 result) {\\n assembly {\\n result := sload(slot)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x903c41cf5b652b90c959c47013f8ad949e435ec7e98fd021fef12388c78c05a2\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyBaseV3.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IForwarder.sol\\\";\\nimport \\\"../proxy/ControllableV3.sol\\\";\\nimport \\\"./StrategyLib2.sol\\\";\\n\\n/// @title Abstract contract for base strategy functionality\\n/// @author a17\\nabstract contract StrategyBaseV3 is IStrategyV3, ControllableV3 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Version of this contract. Adjust manually on each code modification.\\n string public constant STRATEGY_BASE_VERSION = \\\"3.0.1\\\";\\n\\n // *************************************************************\\n // VARIABLES\\n // Keep names and ordering!\\n // Add only in the bottom.\\n // *************************************************************\\n\\n BaseState internal baseState;\\n\\n // *************************************************************\\n // INIT\\n // *************************************************************\\n\\n /// @notice Initialize contract after setup it as proxy implementation\\n function __StrategyBase_init(\\n address controller_,\\n address splitter_\\n ) internal onlyInitializing {\\n _requireInterface(splitter_, InterfaceIds.I_SPLITTER);\\n __Controllable_init(controller_);\\n StrategyLib2.init(baseState, controller_, splitter_);\\n }\\n\\n // *************************************************************\\n // VIEWS\\n // *************************************************************\\n\\n /// @dev Total amount of underlying assets under control of this strategy.\\n function totalAssets() public view override returns (uint) {\\n return IERC20(baseState.asset).balanceOf(address(this)) + investedAssets();\\n }\\n\\n /// @dev See {IERC165-supportsInterface}.\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_STRATEGY_V3 || interfaceId == InterfaceIds.I_STRATEGY_V2 || super.supportsInterface(interfaceId);\\n }\\n\\n function asset() external view returns (address) {\\n return baseState.asset;\\n }\\n\\n function splitter() external view returns (address) {\\n return baseState.splitter;\\n }\\n\\n function compoundRatio() external view returns (uint) {\\n return baseState.compoundRatio;\\n }\\n\\n function performanceReceiver() external view returns (address) {\\n return baseState.performanceReceiver;\\n }\\n\\n function performanceFee() external view returns (uint) {\\n return baseState.performanceFee;\\n }\\n\\n function performanceFeeRatio() external view returns (uint) {\\n return baseState.performanceFeeRatio;\\n }\\n\\n function strategySpecificName() external view returns (string memory) {\\n return baseState.strategySpecificName;\\n }\\n\\n // *************************************************************\\n // VOTER ACTIONS\\n // *************************************************************\\n\\n /// @dev PlatformVoter can change compound ratio for some strategies.\\n /// A strategy can implement another logic for some uniq cases.\\n function setCompoundRatio(uint value) external virtual override {\\n StrategyLib2._changeCompoundRatio(baseState, controller(), value);\\n }\\n\\n // *************************************************************\\n // OPERATOR ACTIONS\\n // *************************************************************\\n\\n /// @dev The name will be used for UI.\\n function setStrategySpecificName(string calldata name) external {\\n StrategyLib2.onlyOperators(controller());\\n StrategyLib2._changeStrategySpecificName(baseState, name);\\n }\\n\\n /// @dev In case of any issue operator can withdraw all from pool.\\n function emergencyExit() external {\\n // check inside lib call\\n\\n _emergencyExitFromPool();\\n StrategyLib2.sendOnEmergencyExit(controller(), baseState.asset, baseState.splitter);\\n }\\n\\n /// @dev Manual claim rewards.\\n function claim() external {\\n StrategyLib2._checkManualClaim(controller());\\n _claim();\\n }\\n\\n // *************************************************************\\n // GOVERNANCE ACTIONS\\n // *************************************************************\\n\\n /// @notice Set performance fee, receiver and ratio\\n function setupPerformanceFee(uint fee_, address receiver_, uint ratio_) external {\\n StrategyLib2.setupPerformanceFee(baseState, fee_, receiver_, ratio_, controller());\\n }\\n\\n // *************************************************************\\n // DEPOSIT/WITHDRAW\\n // *************************************************************\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint /*amount_*/,\\n bool updateTotalAssetsBeforeInvest_\\n ) external override returns (\\n uint strategyLoss\\n ) {\\n uint balance = StrategyLib2._checkInvestAll(baseState.splitter, baseState.asset);\\n\\n if (balance > 0) {\\n strategyLoss = _depositToPool(balance, updateTotalAssetsBeforeInvest_);\\n }\\n\\n return strategyLoss;\\n }\\n\\n /// @dev Withdraws all underlying assets to the vault\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external override returns (uint strategyLoss) {\\n address _splitter = baseState.splitter;\\n address _asset = baseState.asset;\\n\\n uint balance = StrategyLib2._checkSplitterSenderAndGetBalance(_splitter, _asset);\\n\\n (uint expectedWithdrewUSD, uint assetPrice, uint _strategyLoss) = _withdrawAllFromPool();\\n\\n StrategyLib2._withdrawAllToSplitterPostActions(\\n _asset,\\n balance,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n return _strategyLoss;\\n }\\n\\n /// @dev Withdraws some assets to the splitter\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external override returns (uint strategyLoss) {\\n address _splitter = baseState.splitter;\\n address _asset = baseState.asset;\\n\\n uint balance = StrategyLib2._checkSplitterSenderAndGetBalance(_splitter, _asset);\\n\\n if (amount > balance) {\\n uint expectedWithdrewUSD;\\n uint assetPrice;\\n\\n (expectedWithdrewUSD, assetPrice, strategyLoss) = _withdrawFromPool(amount - balance);\\n balance = StrategyLib2.checkWithdrawImpact(\\n _asset,\\n balance,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n }\\n\\n StrategyLib2._withdrawToSplitterPostActions(\\n amount,\\n balance,\\n _asset,\\n _splitter\\n );\\n return strategyLoss;\\n }\\n\\n // *************************************************************\\n // VIRTUAL\\n // These functions must be implemented in the strategy contract\\n // *************************************************************\\n\\n /// @dev Amount of underlying assets invested to the pool.\\n function investedAssets() public view virtual returns (uint);\\n\\n /// @notice Deposit given amount to the pool.\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _depositToPool(\\n uint amount,\\n bool updateTotalAssetsBeforeInvest_\\n ) internal virtual returns (\\n uint strategyLoss\\n );\\n\\n /// @dev Withdraw given amount from the pool.\\n /// @return expectedWithdrewUSD Sum of USD value of each asset in the pool that was withdrawn, decimals of {asset}.\\n /// @return assetPrice Price of the strategy {asset}.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _withdrawFromPool(uint amount) internal virtual returns (\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n uint strategyLoss\\n );\\n\\n /// @dev Withdraw all from the pool.\\n /// @return expectedWithdrewUSD Sum of USD value of each asset in the pool that was withdrawn, decimals of {asset}.\\n /// @return assetPrice Price of the strategy {asset}.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function _withdrawAllFromPool() internal virtual returns (\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n uint strategyLoss\\n );\\n\\n /// @dev If pool support emergency withdraw need to call it for emergencyExit()\\n /// Withdraw assets without impact checking.\\n function _emergencyExitFromPool() internal virtual;\\n\\n /// @dev Claim all possible rewards.\\n function _claim() internal virtual returns (address[] memory rewardTokens, uint[] memory amounts);\\n\\n /// @dev This empty reserved space is put in place to allow future versions to add new\\n /// variables without shifting down storage in the inheritance chain.\\n /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n uint[50 - 7] private __gap;\\n}\\n\",\"keccak256\":\"0xe38a85a74609ad7047635c8d8fc37a12b4e5731903aa1dcc434a1705c09db06f\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/tools/TetuERC165.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/ERC165.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../lib/InterfaceIds.sol\\\";\\n\\n/// @dev Tetu Implementation of the {IERC165} interface extended with helper functions.\\n/// @author bogdoslav\\nabstract contract TetuERC165 is ERC165 {\\n\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == InterfaceIds.I_TETU_ERC165 || super.supportsInterface(interfaceId);\\n }\\n\\n // *************************************************************\\n // HELPER FUNCTIONS\\n // *************************************************************\\n /// @author bogdoslav\\n\\n /// @dev Checks what interface with id is supported by contract.\\n /// @return bool. Do not throws\\n function _isInterfaceSupported(address contractAddress, bytes4 interfaceId) internal view returns (bool) {\\n require(contractAddress != address(0), \\\"Zero address\\\");\\n // check what address is contract\\n uint codeSize;\\n assembly {\\n codeSize := extcodesize(contractAddress)\\n }\\n if (codeSize == 0) return false;\\n\\n try IERC165(contractAddress).supportsInterface(interfaceId) returns (bool isSupported) {\\n return isSupported;\\n } catch {\\n }\\n return false;\\n }\\n\\n /// @dev Checks what interface with id is supported by contract and reverts otherwise\\n function _requireInterface(address contractAddress, bytes4 interfaceId) internal view {\\n require(_isInterfaceSupported(contractAddress, interfaceId), \\\"Interface is not supported\\\");\\n }\\n\\n /// @dev Checks what address is ERC20.\\n /// @return bool. Do not throws\\n function _isERC20(address contractAddress) internal view returns (bool) {\\n require(contractAddress != address(0), \\\"Zero address\\\");\\n // check what address is contract\\n uint codeSize;\\n assembly {\\n codeSize := extcodesize(contractAddress)\\n }\\n if (codeSize == 0) return false;\\n\\n bool totalSupplySupported;\\n try IERC20(contractAddress).totalSupply() returns (uint) {\\n totalSupplySupported = true;\\n } catch {\\n }\\n\\n bool balanceSupported;\\n try IERC20(contractAddress).balanceOf(address(this)) returns (uint) {\\n balanceSupported = true;\\n } catch {\\n }\\n\\n return totalSupplySupported && balanceSupported;\\n }\\n\\n\\n /// @dev Checks what interface with id is supported by contract and reverts otherwise\\n function _requireERC20(address contractAddress) internal view {\\n require(_isERC20(contractAddress), \\\"Not ERC20\\\");\\n }\\n}\\n\",\"keccak256\":\"0xa6eb1009f769fbca986553c7f32af09c9e66c330b4b8c7b8344997001e2cd4f1\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverterCallback.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\n/// @notice TetuConverter sends callback notifications to its user via this interface\\ninterface ITetuConverterCallback {\\n /// @notice Converters calls this function if user should return some amount back.\\n /// f.e. when the health factor is unhealthy and the converter needs more tokens to fix it.\\n /// or when the full repay is required and converter needs to get full amount-to-repay.\\n /// @param asset_ Required asset (either collateral or borrow)\\n /// @param amount_ Required amount of the {asset_}\\n /// @return amountOut Exact amount that borrower has sent to balance of TetuConverter\\n function requirePayAmountBack(address asset_, uint amount_) external returns (uint amountOut);\\n\\n /// @notice TetuConverter calls this function when it sends any amount to user's balance\\n /// @param assets_ Any asset sent to the balance, i.e. inside repayTheBorrow\\n /// @param amounts_ Amount of {asset_} that has been sent to the user's balance\\n function onTransferAmounts(address[] memory assets_, uint[] memory amounts_) external;\\n}\\n\",\"keccak256\":\"0x1ab7657c44e7725e32ef1a25293f1895911943bb25a8d0afb22a218ee4fa9d5b\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3MintCallback.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Callback for IUniswapV3PoolActions#mint\\r\\n/// @notice Any contract that calls IUniswapV3PoolActions#mint must implement this interface\\r\\ninterface IUniswapV3MintCallback {\\r\\n /// @notice Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint.\\r\\n /// @dev In the implementation you must pay the pool tokens owed for the minted liquidity.\\r\\n /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.\\r\\n /// @param amount0Owed The amount of token0 due to the pool for the minted liquidity\\r\\n /// @param amount1Owed The amount of token1 due to the pool for the minted liquidity\\r\\n /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#mint call\\r\\n function uniswapV3MintCallback(\\r\\n uint256 amount0Owed,\\r\\n uint256 amount1Owed,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n}\\r\\n\",\"keccak256\":\"0xb6253f2c332f5e46e278b90b1c6c44cf392e512a5df3d29fc623c950deca19bf\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPairBasedDefaultStateProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Provides access to getDefaultState() of a pair-based strategy\\r\\ninterface IPairBasedDefaultStateProvider {\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n );\\r\\n}\",\"keccak256\":\"0x883b0f9e463485a57aa1baea9aafef64180362d336114a53f6cb8b7a94303d70\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/interfaces/IRebalancingV2Strategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./IPairBasedDefaultStateProvider.sol\\\";\\r\\nimport \\\"./ISetupPairBasedStrategy.sol\\\";\\r\\n\\r\\ninterface IRebalancingV2Strategy is IPairBasedDefaultStateProvider, ISetupPairBasedStrategy {\\r\\n function needRebalance() external view returns (bool);\\r\\n\\r\\n /// @notice Rebalance using borrow/repay only, no swaps\\r\\n /// @param checkNeedRebalance Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\\r\\n function rebalanceNoSwaps(bool checkNeedRebalance) external;\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n function quoteWithdrawByAgg(bytes memory planEntryData) external returns (address tokenToSwap, uint amountToSwap);\\r\\n\\r\\n /// @notice Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool]\\r\\n /// Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt.\\r\\n /// You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\\r\\n /// @dev All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\\r\\n /// @param tokenToSwap_ What token should be swapped to other\\r\\n /// @param aggregator_ Aggregator that should be used on next swap. 0 - use liquidator\\r\\n /// @param amountToSwap_ Amount that should be swapped. 0 - no swap\\r\\n /// @param swapData Swap rote that was prepared off-chain.\\r\\n /// @param planEntryData PLAN_XXX + additional data, see IterationPlanKinds\\r\\n /// @param entryToPool Allow to enter to the pool at the end. Use false if you are going to make several iterations.\\r\\n /// It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment\\r\\n /// 0 - not allowed, 1 - allowed, 2 - allowed only if completed\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions.\\r\\n function withdrawByAggStep(\\r\\n address tokenToSwap_,\\r\\n address aggregator_,\\r\\n uint amountToSwap_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n uint entryToPool\\r\\n ) external returns (bool completed);\\r\\n\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x1ae39d0cc7607cdb9b935e2f6bcb8db8206f180d17fc2230f368509c5173d788\",\"license\":\"MIT\"},\"contracts/interfaces/ISetupPairBasedStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Functions to initialize pair-based strategies\\r\\ninterface ISetupPairBasedStrategy {\\r\\n\\r\\n /// @notice Manually set status of the fuse\\r\\n /// @param status See PairBasedStrategyLib.FuseStatus enum for possible values\\r\\n function setFuseStatus(uint status) external;\\r\\n\\r\\n /// @notice Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n /// @param values Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function setFuseThresholds(uint[4] memory values) external;\\r\\n function setStrategyProfitHolder(address strategyProfitHolder) external;\\r\\n\\r\\n /// @notice Set withdrawDone value.\\r\\n /// When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying.\\r\\n /// After completion of the conversion withdrawDone can be set to 1.\\r\\n /// So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\\r\\n /// @param done 0 - full withdraw required, 1 - full withdraw was done\\r\\n function setWithdrawDone(uint done) external;\\r\\n}\\r\\n\",\"keccak256\":\"0xbe3f6fdf20e05b353202bfd42cb087c106ac055310fb3af80b56a4cda2a86a79\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppPlatforms.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary AppPlatforms {\\r\\n string public constant UNIV3 = \\\"UniswapV3\\\";\\r\\n string public constant BALANCER = \\\"Balancer\\\";\\r\\n string public constant ALGEBRA = \\\"Algebra\\\";\\r\\n string public constant KYBER = \\\"Kyber\\\";\\r\\n string public constant PANCAKE = \\\"Pancake\\\"; // https://pancakeswap.finance/\\r\\n}\\r\\n\",\"keccak256\":\"0x28767f209dd412f52bc6274d3d95e4fb1fc03f6e8db183c13efd09ed82741b4b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyBaseV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverterCallback.sol\\\";\\r\\nimport \\\"./ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"./DepositorBase.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/////////////////////////////////////////////////////////////////////\\r\\n/// TERMS\\r\\n/// Main asset == underlying: the asset deposited to the vault by users\\r\\n/// Secondary assets: all assets deposited to the internal pool except the main asset\\r\\n/////////////////////////////////////////////////////////////////////\\r\\n// History:\\r\\n// 3.0.1 refactoring of emergency exit\\r\\n// 3.1.0 use bookkeeper, new set of events\\r\\n// 3.1.2 scb-867\\r\\n// 3.1.3,4 scb-900, scb-914\\r\\n// 3.1.5 use approveForced for aggregators\\r\\n// 3.1.6 dynamic insurance\\r\\n\\r\\n/// @title Abstract contract for base Converter strategy functionality\\r\\n/// @notice All depositor assets must be correlated (ie USDC/USDT/DAI)\\r\\n/// @author bogdoslav, dvpublic, a17\\r\\nabstract contract ConverterStrategyBase is IConverterStrategyBase, ITetuConverterCallback, DepositorBase, StrategyBaseV3 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region -------------------------------------------------------- DATA TYPES\\r\\n struct WithdrawUniversalLocal {\\r\\n ITetuConverter converter;\\r\\n /// @notice Target asset that should be received on balance.\\r\\n /// It's underlying in _withdrawUniversal(), but it can be any other asset in requirePayAmountBack()\\r\\n address theAsset;\\r\\n /// @notice List of tokens received by _depositorPoolAssets()\\r\\n address[] tokens;\\r\\n /// @notice Index of the {asset} in {tokens}\\r\\n uint indexTheAsset;\\r\\n /// @notice Initial balance of the [asset}\\r\\n uint balanceBefore;\\r\\n uint indexUnderlying;\\r\\n }\\r\\n //endregion -------------------------------------------------------- DATA TYPES\\r\\n\\r\\n //region -------------------------------------------------------- CONSTANTS\\r\\n\\r\\n /// @dev Version of this contract. Adjust manually on each code modification.\\r\\n string public constant CONVERTER_STRATEGY_BASE_VERSION = \\\"3.1.6\\\";\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n /// @notice If we need to withdraw A, we always tries to receive on balance A + delta\\r\\n /// and have at least delta on balance after withdraw to prevent situation when we have debts\\r\\n /// but don't have any liquidity to pay the debts and receive locked collaterals back\\r\\n ///\\r\\n /// Delta will be in the range [GAP_WITHDRAW...2 * GAP_WITHDRAW]\\r\\n uint internal constant GAP_WITHDRAW = 1_000;\\r\\n //endregion -------------------------------------------------------- CONSTANTS\\r\\n\\r\\n //region -------------------------------------------------------- VARIABLES\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n // Keep names and ordering!\\r\\n // Add only in the bottom and don't forget to decrease gap variable\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Minimum token amounts that can be liquidated\\r\\n /// @dev These thresholds are used to workaround dust problems in many other cases, not during liquidation only\\r\\n mapping(address => uint) public liquidationThresholds;\\r\\n\\r\\n /// @notice Internal variables of ConverterStrategyBase\\r\\n ConverterStrategyBaseState internal _csbs;\\r\\n //endregion -------------------------------------------------------- VARIABLES\\r\\n\\r\\n //region -------------------------------------------------------- Getters\\r\\n function converter() external view returns (ITetuConverter) {\\r\\n return _csbs.converter;\\r\\n }\\r\\n\\r\\n function reinvestThresholdPercent() external view returns (uint) {\\r\\n return _csbs.reinvestThresholdPercent;\\r\\n }\\r\\n\\r\\n function debtToInsurance() external view returns (int) {\\r\\n return _csbs.debtToInsurance;\\r\\n }\\r\\n //endregion -------------------------------------------------------- Getters\\r\\n\\r\\n //region -------------------------------------------------------- Events\\r\\n event OnDepositorEnter(uint[] amounts, uint[] consumedAmounts);\\r\\n event OnDepositorExit(uint liquidityAmount, uint[] withdrawnAmounts);\\r\\n event OnDepositorEmergencyExit(uint[] withdrawnAmounts);\\r\\n event OnHardWorkEarnedLost(\\r\\n uint investedAssetsNewPrices,\\r\\n uint earnedByPrices,\\r\\n uint earnedHandleRewards,\\r\\n uint lostHandleRewards,\\r\\n uint earnedDeposit,\\r\\n uint lostDeposit,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n );\\r\\n //endregion -------------------------------------------------------- Events\\r\\n\\r\\n //region -------------------------------------------------------- Initialization and configuration\\r\\n\\r\\n /// @notice Initialize contract after setup it as proxy implementation\\r\\n function __ConverterStrategyBase_init(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address converter_\\r\\n ) internal onlyInitializing {\\r\\n __StrategyBase_init(controller_, splitter_);\\r\\n _csbs.converter = ITetuConverter(converter_);\\r\\n\\r\\n // 1% by default\\r\\n _csbs.reinvestThresholdPercent = DENOMINATOR / 100;\\r\\n emit ConverterStrategyBaseLib2.ReinvestThresholdPercentChanged(DENOMINATOR / 100);\\r\\n }\\r\\n\\r\\n /// @dev Liquidation thresholds are used to detect dust in many cases, not only in liquidation case\\r\\n /// @param amount Min amount of token allowed to liquidate, token's decimals are used.\\r\\n function setLiquidationThreshold(address token, uint amount) external {\\r\\n ConverterStrategyBaseLib2.checkLiquidationThresholdChanged(controller(), token, amount);\\r\\n liquidationThresholds[token] = amount;\\r\\n }\\r\\n\\r\\n /// @param percent_ New value of the percent, decimals = {REINVEST_THRESHOLD_PERCENT_DENOMINATOR}\\r\\n function setReinvestThresholdPercent(uint percent_) external {\\r\\n ConverterStrategyBaseLib2.checkReinvestThresholdPercentChanged(controller(), percent_);\\r\\n _csbs.reinvestThresholdPercent = percent_;\\r\\n }\\r\\n //endregion -------------------------------------------------------- Initialization and configuration\\r\\n\\r\\n //region -------------------------------------------------------- Deposit to the pool\\r\\n\\r\\n /// @notice Amount of underlying assets converted to pool assets and invested to the pool.\\r\\n function investedAssets() override public view virtual returns (uint) {\\r\\n return _csbs.investedAssets;\\r\\n }\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n function _depositToPool(uint amount_, bool updateTotalAssetsBeforeInvest_) override internal virtual returns (\\r\\n uint strategyLoss\\r\\n ){\\r\\n (uint updatedInvestedAssets, uint earnedByPrices) = _fixPriceChanges(updateTotalAssetsBeforeInvest_);\\r\\n (strategyLoss,,,) = _depositToPoolUniversal(amount_, earnedByPrices, updatedInvestedAssets);\\r\\n }\\r\\n\\r\\n /// @notice Deposit {amount_} to the pool, send {earnedByPrices_} to insurance.\\r\\n /// totalAsset will decrease on earnedByPrices_ and sharePrice won't change after all recalculations.\\r\\n /// @dev We need to deposit {amount_} and withdraw {earnedByPrices_} here\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param earnedByPrices_ Profit received because of price changing\\r\\n /// @param investedAssets_ Invested assets value calculated with updated prices\\r\\n /// @return strategyLoss Loss happened on the depositing. It doesn't include any price-changing losses\\r\\n /// @return amountSentToInsurance Price-changing-profit that was sent to the insurance\\r\\n /// @return investedAssetsAfter Value of csbs.investedAssets after the call of the function\\r\\n /// @return balanceAfter Balance of the underlying after the call of the function\\r\\n function _depositToPoolUniversal(uint amount_, uint earnedByPrices_, uint investedAssets_) internal virtual returns (\\r\\n uint strategyLoss,\\r\\n uint amountSentToInsurance,\\r\\n uint investedAssetsAfter,\\r\\n uint balanceAfter\\r\\n ){\\r\\n address _asset = baseState.asset;\\r\\n\\r\\n uint amountToDeposit = amount_ > earnedByPrices_\\r\\n ? amount_ - earnedByPrices_\\r\\n : 0;\\r\\n\\r\\n // skip deposit for small amounts\\r\\n bool needToDeposit = amountToDeposit > _csbs.reinvestThresholdPercent * investedAssets_ / DENOMINATOR;\\r\\n uint balanceBefore = AppLib.balance(_asset);\\r\\n\\r\\n // send earned-by-prices to the insurance, ignore dust values\\r\\n if (earnedByPrices_ > AppLib._getLiquidationThreshold(liquidationThresholds[_asset])) {\\r\\n if (needToDeposit || balanceBefore >= earnedByPrices_) {\\r\\n (amountSentToInsurance,) = ConverterStrategyBaseLib2.sendToInsurance(\\r\\n _asset,\\r\\n earnedByPrices_,\\r\\n baseState.splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceBefore\\r\\n );\\r\\n } else {\\r\\n // needToDeposit is false and we don't have enough amount to cover earned-by-prices, we need to withdraw\\r\\n (,, strategyLoss, amountSentToInsurance) = _withdrawUniversal(0, earnedByPrices_, investedAssets_);\\r\\n }\\r\\n }\\r\\n\\r\\n // make deposit\\r\\n if (needToDeposit) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(_asset);\\r\\n\\r\\n // prepare array of amounts ready to deposit, borrow missed amounts\\r\\n uint[] memory amounts = _beforeDeposit(_csbs.converter, amountToDeposit, tokens, indexAsset);\\r\\n\\r\\n // make deposit, actually consumed amounts can be different from the desired amounts\\r\\n if (!ConverterStrategyBaseLib2.findZeroAmount(amounts)) {\\r\\n\\r\\n // we cannot enter to pool if at least one of amounts is zero\\r\\n // we check != 0 and don't use thresholds because some strategies allow to enter to the pool with amount < liquidation threshold\\r\\n (uint[] memory consumedAmounts,) = _depositorEnter(amounts);\\r\\n emit OnDepositorEnter(amounts, consumedAmounts);\\r\\n }\\r\\n }\\r\\n\\r\\n // update _investedAssets with new deposited amount\\r\\n investedAssetsAfter = _updateInvestedAssets();\\r\\n balanceAfter = AppLib.balance(_asset);\\r\\n\\r\\n // we need to compensate difference if during deposit we lost some assets\\r\\n (,strategyLoss) = ConverterStrategyBaseLib2._registerIncome(\\r\\n investedAssets_ + balanceBefore,\\r\\n investedAssetsAfter + balanceAfter + amountSentToInsurance\\r\\n );\\r\\n\\r\\n return (strategyLoss, amountSentToInsurance, investedAssetsAfter, balanceAfter);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Deposit to the pool\\r\\n\\r\\n //region -------------------------------------------------------- Convert amounts before deposit\\r\\n\\r\\n /// @notice Prepare {tokenAmounts} to be passed to depositorEnter\\r\\n /// @dev Override this function to customize entry kind\\r\\n /// @param amount_ The amount of main asset that should be invested\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmounts Amounts of depositor's assets ready to invest (this array can be passed to depositorEnter)\\r\\n function _beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_\\r\\n ) internal virtual returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // calculate required collaterals for each token and temporary save them to tokenAmounts\\r\\n (uint[] memory weights, uint totalWeight) = _depositorPoolWeights();\\r\\n return ConverterStrategyBaseLib.beforeDeposit(\\r\\n converter_,\\r\\n amount_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n weights,\\r\\n totalWeight,\\r\\n liquidationThresholds\\r\\n );\\r\\n }\\r\\n //endregion -------------------------------------------------------- Convert amounts before deposit\\r\\n\\r\\n //region -------------------------------------------------------- Get requested amount\\r\\n\\r\\n /// @notice Initialize members of {v}\\r\\n /// @param underlying true if asset_ is underlying\\r\\n function _initWithdrawUniversalLocal(address asset_, WithdrawUniversalLocal memory v, bool underlying) internal view {\\r\\n v.tokens = _depositorPoolAssets();\\r\\n v.theAsset = asset_;\\r\\n v.converter = _csbs.converter;\\r\\n v.indexTheAsset = AppLib.getAssetIndex(v.tokens, asset_);\\r\\n v.balanceBefore = AppLib.balance(asset_);\\r\\n v.indexUnderlying = underlying ? v.indexTheAsset : AppLib.getAssetIndex(v.tokens, baseState.asset);\\r\\n }\\r\\n\\r\\n /// @notice Get the specified {amount} of the given {v.asset} on the balance\\r\\n /// @dev Ensures that either all debts are closed, or a non-zero amount remains on the balance or in the pool to pay off the debts\\r\\n /// @param amount_ Required amount of {v.asset}. Use type(uint).max to withdraw all\\r\\n /// @return expectedTotalAssetAmount Expected amount of {v.asset} that should be received on the balance\\r\\n /// Expected total amount of given asset after all withdraws, conversions, swaps and repays\\r\\n function _makeRequestedAmount(uint amount_, WithdrawUniversalLocal memory v) internal virtual returns ( // it's virtual to simplify unit testing\\r\\n uint expectedTotalAssetAmount\\r\\n ) {\\r\\n uint depositorLiquidity = _depositorLiquidity();\\r\\n\\r\\n // calculate how much liquidity we need to withdraw for getting at least requested amount of the {v.asset}\\r\\n uint[] memory quoteAmounts = _depositorQuoteExit(depositorLiquidity);\\r\\n uint liquidityAmountToWithdraw = ConverterStrategyBaseLib2.getLiquidityAmount(\\r\\n amount_,\\r\\n v.tokens,\\r\\n v.indexTheAsset,\\r\\n v.converter,\\r\\n quoteAmounts,\\r\\n depositorLiquidity,\\r\\n v.indexUnderlying\\r\\n );\\r\\n\\r\\n if (liquidityAmountToWithdraw != 0) {\\r\\n uint[] memory withdrawnAmounts = _depositorExit(liquidityAmountToWithdraw, false);\\r\\n // the depositor is able to use less liquidity than it was asked, i.e. Balancer-depositor leaves some BPT unused\\r\\n // use what exactly was withdrew instead of the expectation\\r\\n // assume that liquidity cannot increase in _depositorExit\\r\\n liquidityAmountToWithdraw = depositorLiquidity - _depositorLiquidity();\\r\\n emit OnDepositorExit(liquidityAmountToWithdraw, withdrawnAmounts);\\r\\n }\\r\\n\\r\\n // try to receive at least requested amount of the {v.asset} on the balance\\r\\n uint expectedBalance = ConverterStrategyBaseLib.makeRequestedAmount(\\r\\n v.tokens,\\r\\n v.indexTheAsset,\\r\\n v.converter,\\r\\n AppLib._getLiquidator(controller()),\\r\\n (amount_ == type(uint).max ? amount_ : v.balanceBefore + amount_), // current balance + the amount required to be withdrawn on balance\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n require(expectedBalance >= v.balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n return expectedBalance - v.balanceBefore;\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------------- Get requested amount\\r\\n\\r\\n //region -------------------------------------------------------- Withdraw from the pool\\r\\n\\r\\n function _beforeWithdraw(uint /*amount*/) internal virtual {\\r\\n // do nothing\\r\\n }\\r\\n\\r\\n /// @notice Withdraw given amount from the pool.\\r\\n /// @param amount Amount to be withdrawn in terms of the asset in addition to the exist balance.\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing (in USD, decimals of the {asset})\\r\\n /// @return assetPrice Price of the {asset} from the price oracle\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _withdrawFromPool(uint amount) override internal virtual returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss\\r\\n ) {\\r\\n // calculate profit/loss because of price changes, try to compensate the loss from the insurance\\r\\n (uint investedAssetsNewPrices, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n (expectedWithdrewUSD, assetPrice, strategyLoss,) = _withdrawUniversal(amount, earnedByPrices, investedAssetsNewPrices);\\r\\n }\\r\\n\\r\\n /// @notice Withdraw all from the pool.\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing\\r\\n /// @return assetPrice Price of the {asset} taken from the price oracle\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _withdrawAllFromPool() override internal virtual returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss\\r\\n ) {\\r\\n return _withdrawFromPool(type(uint).max);\\r\\n }\\r\\n\\r\\n /// @dev The function is virtual to simplify unit testing\\r\\n /// @param amount_ Amount to be trying to withdrawn. Max uint means attempt to withdraw all possible invested assets.\\r\\n /// @param earnedByPrices_ Additional amount that should be withdrawn and send to the insurance\\r\\n /// @param investedAssets_ Value of invested assets recalculated using current prices\\r\\n /// @return expectedWithdrewUSD The value that we should receive after withdrawing in terms of USD value of each asset in the pool\\r\\n /// @return assetPrice Price of the {asset} taken from the price oracle\\r\\n /// @return strategyLoss Loss before withdrawing: [new-investedAssets - old-investedAssets]\\r\\n /// @return amountSentToInsurance Actual amount of underlying sent to the insurance\\r\\n function _withdrawUniversal(uint amount_, uint earnedByPrices_, uint investedAssets_) virtual internal returns (\\r\\n uint expectedWithdrewUSD,\\r\\n uint assetPrice,\\r\\n uint strategyLoss,\\r\\n uint amountSentToInsurance\\r\\n ) {\\r\\n // amount to withdraw; we add a little gap to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n uint amount = amount_ == type(uint).max\\r\\n ? amount_\\r\\n : (amount_ + earnedByPrices_) * (DENOMINATOR + GAP_WITHDRAW) / DENOMINATOR;\\r\\n _beforeWithdraw(amount);\\r\\n\\r\\n if (amount != 0 && investedAssets_ != 0) {\\r\\n WithdrawUniversalLocal memory v;\\r\\n _initWithdrawUniversalLocal(baseState.asset, v, true);\\r\\n\\r\\n // get at least requested amount of the underlying on the balance\\r\\n assetPrice = ConverterStrategyBaseLib2.getAssetPriceFromConverter(v.converter, v.theAsset);\\r\\n expectedWithdrewUSD = AppLib.sub0(_makeRequestedAmount(amount, v), earnedByPrices_) * assetPrice / 1e18;\\r\\n\\r\\n (amountSentToInsurance, strategyLoss) = ConverterStrategyBaseLib2.calculateIncomeAfterWithdraw(\\r\\n baseState.splitter,\\r\\n v.theAsset,\\r\\n investedAssets_,\\r\\n v.balanceBefore,\\r\\n earnedByPrices_,\\r\\n _updateInvestedAssets()\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n expectedWithdrewUSD,\\r\\n assetPrice,\\r\\n strategyLoss,\\r\\n amountSentToInsurance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Withdraw all amounts from the pool using minimum actions (it skips claiming rewards, fees and so on)\\r\\n function _emergencyExitFromPool() override internal virtual {\\r\\n uint[] memory withdrawnAmounts = _depositorEmergencyExit();\\r\\n emit OnDepositorEmergencyExit(withdrawnAmounts);\\r\\n // we don't convert amounts to main asset to avoid any excess actions\\r\\n // update of invested assets is necessary in any case\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n //endregion -------------------------------------------------------- Withdraw from the pool\\r\\n\\r\\n //region -------------------------------------------------------- Claim rewards\\r\\n\\r\\n /// @notice Claim all possible rewards.\\r\\n function _claim() override internal virtual returns (address[] memory rewardTokensOut, uint[] memory amountsOut) {\\r\\n // get rewards from the Depositor\\r\\n (address[] memory rewardTokens, uint[] memory rewardAmounts, uint[] memory balancesBefore) = _depositorClaimRewards();\\r\\n\\r\\n (rewardTokensOut, amountsOut) = ConverterStrategyBaseLib2.claimConverterRewards(\\r\\n _csbs.converter,\\r\\n _depositorPoolAssets(),\\r\\n rewardTokens,\\r\\n rewardAmounts,\\r\\n balancesBefore\\r\\n );\\r\\n }\\r\\n\\r\\n /// @dev Call recycle process and send tokens to forwarder.\\r\\n /// Need to be separated from the claim process - the claim can be called by operator for other purposes.\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Total performance fee in terms of underlying\\r\\n function _rewardsLiquidation(address[] memory rewardTokens_, uint[] memory rewardAmounts_) internal returns (\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n ) {\\r\\n if (rewardTokens_.length != 0) {\\r\\n (paidDebtToInsurance, amountPerf) = ConverterStrategyBaseLib.recycle(\\r\\n baseState,\\r\\n _csbs,\\r\\n _depositorPoolAssets(),\\r\\n controller(),\\r\\n liquidationThresholds,\\r\\n rewardTokens_,\\r\\n rewardAmounts_\\r\\n );\\r\\n }\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Claim rewards\\r\\n\\r\\n //region -------------------------------------------------------- Hardwork\\r\\n\\r\\n /// @notice A virtual handler to make any action before hardwork\\r\\n /// @return True if the hardwork should be skipped\\r\\n function _preHardWork(bool reInvest) internal virtual returns (bool) {\\r\\n reInvest; // hide warning\\r\\n return false;\\r\\n }\\r\\n\\r\\n /// @notice A virtual handler to make any action after hardwork\\r\\n function _postHardWork() internal virtual {}\\r\\n\\r\\n /// @notice Is strategy ready to hard work\\r\\n function isReadyToHardWork() override external virtual view returns (bool) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n return true;\\r\\n }\\r\\n\\r\\n /// @notice Do hard work with reinvesting\\r\\n /// @return earned Earned amount in terms of {asset}\\r\\n /// @return lost Lost amount in terms of {asset}\\r\\n function doHardWork() override public returns (uint earned, uint lost) {\\r\\n require(msg.sender == baseState.splitter, StrategyLib2.DENIED);\\r\\n return _doHardWork(true);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards, do _processClaims() after claiming, calculate earned and lost amounts\\r\\n /// @return earned The amount of earned rewards.\\r\\n /// @return lost The amount of lost rewards.\\r\\n /// @return assetBalanceAfterClaim The asset balance after claiming rewards.\\r\\n /// @return paidDebtToInsurance A part of {earned} spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function _handleRewards() internal virtual returns (\\r\\n uint earned,\\r\\n uint lost,\\r\\n uint assetBalanceAfterClaim,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n );\\r\\n\\r\\n /// @param reInvest Deposit to pool all available amount if it's greater than the threshold\\r\\n /// @return earned Earned amount in terms of {asset}\\r\\n /// @return lost Lost amount in terms of {asset}\\r\\n function _doHardWork(bool reInvest) internal returns (uint earned, uint lost) {\\r\\n // ATTENTION! splitter will not cover the loss if it is lower than profit\\r\\n (uint investedAssetsNewPrices, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n\\r\\n if (!_preHardWork(reInvest)) {\\r\\n // claim rewards and get current asset balance\\r\\n (uint earned1, uint lost1, uint assetBalance, uint paidDebtToInsurance, uint amountPerf) = _handleRewards();\\r\\n\\r\\n // re-invest income\\r\\n (uint investedAssetsAfterHandleRewards,,) = _calcInvestedAssets();\\r\\n\\r\\n { // send earnedByPrices to the insurance, optionally make deposit (and even withdraw if necessary)\\r\\n (, uint amountSentToInsurance, uint investedAssetsAfterDeposit, uint balanceAfterDeposit) = _depositToPoolUniversal(\\r\\n reInvest\\r\\n && investedAssetsAfterHandleRewards != 0\\r\\n && assetBalance > _csbs.reinvestThresholdPercent * investedAssetsAfterHandleRewards / DENOMINATOR\\r\\n ? assetBalance\\r\\n : 0,\\r\\n earnedByPrices,\\r\\n investedAssetsAfterHandleRewards\\r\\n );\\r\\n\\r\\n (earned, lost) = ConverterStrategyBaseLib2._registerIncome(\\r\\n investedAssetsAfterHandleRewards + assetBalance, // assets in use before deposit\\r\\n investedAssetsAfterDeposit + balanceAfterDeposit + amountSentToInsurance // assets in use after deposit\\r\\n );\\r\\n }\\r\\n\\r\\n _postHardWork();\\r\\n emit OnHardWorkEarnedLost(investedAssetsNewPrices, earnedByPrices, earned1, lost1, earned, lost, paidDebtToInsurance, amountPerf);\\r\\n\\r\\n // Excluded from earned two values: performance fee and amount paid to cover debt before the insurance\\r\\n // Amount sent to the forwarder is still included to the result earned amount.\\r\\n earned = AppLib.sub0(earned + earned1, paidDebtToInsurance + amountPerf);\\r\\n lost += lost1;\\r\\n }\\r\\n\\r\\n // register amount paid for the debts and amount received for the provided collaterals\\r\\n ConverterStrategyBaseLib2.registerBorrowResults(_csbs.converter, baseState.asset);\\r\\n\\r\\n return (earned, lost);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Hardwork\\r\\n\\r\\n //region -------------------------------------------------------- InvestedAssets Calculations\\r\\n\\r\\n /// @notice Updates cached _investedAssets to actual value\\r\\n /// @dev Should be called after deposit / withdraw / claim; virtual - for ut\\r\\n function _updateInvestedAssets() internal returns (uint investedAssetsOut) {\\r\\n (investedAssetsOut,,) = _calcInvestedAssets();\\r\\n _csbs.investedAssets = investedAssetsOut;\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @return amountOut Invested asset amount under control (in terms of {asset})\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets() internal returns (uint amountOut, uint[] memory prices, uint[] memory decs) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(baseState.asset);\\r\\n return ConverterStrategyBaseLib2.calcInvestedAssets(\\r\\n tokens,\\r\\n _getDepositorQuoteExitAmountsOut(tokens),\\r\\n indexAsset,\\r\\n _csbs.converter,\\r\\n true\\r\\n );\\r\\n }\\r\\n\\r\\n function calcInvestedAssets() external returns (uint investedAssetsOut) {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n (investedAssetsOut,,) = _calcInvestedAssets();\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount of deposited tokens that can be received from the pool after withdrawing all liquidity.\\r\\n function _getDepositorQuoteExitAmountsOut(address[] memory tokens) internal returns (\\r\\n uint[] memory depositorQuoteExitAmountsOut\\r\\n ) {\\r\\n uint liquidity = _depositorLiquidity();\\r\\n return liquidity == 0\\r\\n ? new uint[](tokens.length)\\r\\n : _depositorQuoteExit(liquidity);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing. Try to cover the loss, send the profit to the insurance\\r\\n /// @param updateInvestedAssetsAmount_ If false - just return current value of invested assets\\r\\n /// @return investedAssetsOut Updated value of {_investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n /// It's too dangerous to try to get this amount here because of the problem \\\"borrow-repay is not allowed in a single block\\\"\\r\\n /// So, we need to handle it in the caller code.\\r\\n function _fixPriceChanges(bool updateInvestedAssetsAmount_) internal returns (uint investedAssetsOut, uint earnedOut) {\\r\\n if (updateInvestedAssetsAmount_) {\\r\\n (address[] memory tokens, uint indexAsset) = _getTokens(baseState.asset);\\r\\n (investedAssetsOut, earnedOut) = ConverterStrategyBaseLib2.fixPriceChanges(\\r\\n _csbs,\\r\\n baseState,\\r\\n _getDepositorQuoteExitAmountsOut(tokens),\\r\\n tokens,\\r\\n indexAsset\\r\\n );\\r\\n } else {\\r\\n (investedAssetsOut, earnedOut) = (_csbs.investedAssets, 0);\\r\\n }\\r\\n }\\r\\n //endregion -------------------------------------------------------- InvestedAssets Calculations\\r\\n\\r\\n //region -------------------------------------------------------- ITetuConverterCallback\\r\\n\\r\\n /// @notice Converters asks to send some amount back.\\r\\n /// The results depend on whether the required amount is on the balance:\\r\\n /// 1. The {amount_} exists on the balance: send the amount to TetuConverter, return {amount_}\\r\\n /// 2. The {amount_} doesn't exist on the balance. Try to receive the {amount_}.\\r\\n /// 2.1. if the required amount is received: return {amount_}\\r\\n /// 2.2. if less amount X (X < {amount_}) is received return X - gap\\r\\n /// In the case 2 no amount is send to TetuConverter.\\r\\n /// Converter should make second call of requirePayAmountBack({amountOut}) to receive the assets.\\r\\n /// @param theAsset_ Required asset (either collateral or borrow), it can be NOT underlying\\r\\n /// @param amount_ Required amount of {theAsset_}\\r\\n /// @return amountOut Amount that was send OR can be claimed on the next call.\\r\\n /// The caller should control own balance to know if the amount was actually send\\r\\n /// (because we need compatibility with exist not-NSR strategies)\\r\\n function requirePayAmountBack(address theAsset_, uint amount_) external override returns (uint amountOut) {\\r\\n WithdrawUniversalLocal memory v;\\r\\n _initWithdrawUniversalLocal(theAsset_, v, false);\\r\\n require(msg.sender == address(v.converter), StrategyLib.DENIED);\\r\\n require(amount_ != 0, AppErrors.ZERO_VALUE);\\r\\n require(v.indexTheAsset != type(uint).max, AppErrors.WRONG_ASSET);\\r\\n\\r\\n (uint _investedAssets, uint earnedByPrices) = _fixPriceChanges(true);\\r\\n v.balanceBefore = ConverterStrategyBaseLib2.sendProfitGetAssetBalance(theAsset_, v.balanceBefore, _investedAssets, earnedByPrices, baseState);\\r\\n\\r\\n // amount to withdraw; we add a little gap to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n // At first we add only 1 gap.\\r\\n // This is min allowed amount that we should have on balance to be able to send {amount_} to the converter\\r\\n uint amountPlusGap = amount_ * (DENOMINATOR + GAP_WITHDRAW) / DENOMINATOR;\\r\\n\\r\\n if (v.balanceBefore >= amountPlusGap) {\\r\\n // the requested amount is available, send it to the converter\\r\\n IERC20(theAsset_).safeTransfer(address(v.converter), amount_);\\r\\n amountOut = amount_;\\r\\n } else {\\r\\n // the requested amount is not available\\r\\n // so, we cannot send anything to converter in this call\\r\\n // try to receive requested amount to balance\\r\\n // we should receive amount with extra gap, where gap is in the range (GAP_WITHDRAW, 2 * GAP_WITHDRAW]\\r\\n // The caller will be able to claim requested amount (w/o extra gap) in the next call\\r\\n if (_investedAssets == 0) {\\r\\n // there are no invested amounts, we can use amount on balance only\\r\\n // but we cannot send all amount, we should keep not zero amount on balance\\r\\n // to avoid situation \\\"opened debts, no liquidity to pay\\\"\\r\\n // as soon as the converter asks for payment, we still have an opened debt..\\r\\n amountOut = v.balanceBefore * DENOMINATOR / (DENOMINATOR + GAP_WITHDRAW);\\r\\n } else {\\r\\n uint amountTwoGaps = amount_ * (DENOMINATOR + 2 * GAP_WITHDRAW) / DENOMINATOR;\\r\\n // get at least requested amount of {theAsset_} on the balance\\r\\n _makeRequestedAmount(amountTwoGaps - v.balanceBefore, v);\\r\\n\\r\\n uint balanceAfter = AppLib.balance(theAsset_);\\r\\n amountOut = balanceAfter > amountPlusGap\\r\\n ? amount_\\r\\n : balanceAfter * DENOMINATOR / (DENOMINATOR + GAP_WITHDRAW);\\r\\n }\\r\\n }\\r\\n\\r\\n // update invested assets anyway, even if we suppose it will be called in other places\\r\\n _updateInvestedAssets();\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n\\r\\n /// @notice TetuConverter calls this function when it sends any amount to user's balance\\r\\n /// @param assets_ Any asset sent to the balance, i.e. inside repayTheBorrow\\r\\n /// @param amounts_ Amount of {asset_} that has been sent to the user's balance\\r\\n function onTransferAmounts(address[] memory assets_, uint[] memory amounts_) external override {\\r\\n require(msg.sender == address(_csbs.converter), StrategyLib2.DENIED);\\r\\n require(assets_.length == amounts_.length, AppErrors.INCORRECT_LENGTHS);\\r\\n\\r\\n // TetuConverter is able two call this function in two cases:\\r\\n // 1) rebalancing (the health factor of some borrow is too low)\\r\\n // 2) forcible closing of the borrow\\r\\n // In both cases we update invested assets value here\\r\\n // and avoid fixing any related losses in hardwork\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n //endregion -------------------------------------------------------- ITetuConverterCallback\\r\\n\\r\\n //region -------------------------------------------------------- Others\\r\\n\\r\\n /// @notice Unlimited capacity by default\\r\\n function capacity() external virtual view returns (uint) {\\r\\n return 2 ** 255;\\r\\n // almost same as type(uint).max but more gas efficient\\r\\n }\\r\\n\\r\\n /// @return tokens Result of {_depositorPoolAssets}\\r\\n /// @return indexAsset Index of the underlying in {tokens}\\r\\n function _getTokens(address asset_) internal view returns (address[] memory tokens, uint indexAsset) {\\r\\n tokens = _depositorPoolAssets();\\r\\n indexAsset = AppLib.getAssetIndex(tokens, asset_);\\r\\n require(indexAsset != type(uint).max, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n //endregion -------------------------------------------------------- Others\\r\\n\\r\\n\\r\\n /// @dev This empty reserved space is put in place to allow future versions to add new\\r\\n /// variables without shifting down storage in the inheritance chain.\\r\\n /// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\r\\n uint[50 - 4] private __gap; // 50 - count of variables\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x2e2d17bb76aafd3fdb2f978dc92e80ae1125257e0b6c7d0a4238fca9d7ab8891\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/DepositorBase.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Abstract base Depositor contract.\\r\\n/// @notice Converter strategies should inherit xDepositor.\\r\\n/// @notice All communication with external pools should be done at inherited contract\\r\\n/// @author bogdoslav\\r\\nabstract contract DepositorBase {\\r\\n\\r\\n /// @notice Returns pool assets\\r\\n function _depositorPoolAssets() internal virtual view returns (address[] memory assets);\\r\\n\\r\\n /// @notice Returns pool token proportions\\r\\n function _depositorPoolWeights() internal virtual view returns (uint[] memory weights, uint total);\\r\\n\\r\\n /// @notice Returns pool token reserves\\r\\n function _depositorPoolReserves() internal virtual view returns (uint[] memory reserves);\\r\\n\\r\\n /// @notice Returns depositor's pool shares / lp token amount\\r\\n function _depositorLiquidity() internal virtual view returns (uint);\\r\\n\\r\\n //// @notice Total amount of LP tokens in the depositor\\r\\n function _depositorTotalSupply() internal view virtual returns (uint);\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n /// @dev Depositor must care about tokens approval by itself.\\r\\n function _depositorEnter(uint[] memory amountsDesired_) internal virtual returns (\\r\\n uint[] memory amountsConsumed,\\r\\n uint liquidityOut\\r\\n );\\r\\n\\r\\n /// @notice Withdraw given lp amount from the pool.\\r\\n /// @param liquidityAmount Amount of liquidity to be converted\\r\\n /// If requested liquidityAmount >= invested, then should make full exit.\\r\\n /// @param emergency Emergency exit (only withdraw, don't claim any rewards or make any other additional actions)\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorExit(uint liquidityAmount, bool emergency) internal virtual returns (uint[] memory amountsOut);\\r\\n\\r\\n /// @notice Quotes output for given lp amount from the pool.\\r\\n /// @dev Write function with read-only behavior. BalanceR's depositor requires not-view.\\r\\n /// @param liquidityAmount Amount of liquidity to be converted\\r\\n /// If requested liquidityAmount >= invested, then should make full exit.\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorQuoteExit(uint liquidityAmount) internal virtual returns (uint[] memory amountsOut);\\r\\n\\r\\n /// @dev If pool supports emergency withdraw need to call it for emergencyExit()\\r\\n /// @return amountsOut The order of amounts is the same as in {_depositorPoolAssets}\\r\\n function _depositorEmergencyExit() internal virtual returns (uint[] memory amountsOut) {\\r\\n uint liquidity = _depositorLiquidity();\\r\\n return liquidity == 0\\r\\n ? new uint[](_depositorPoolAssets().length)\\r\\n : _depositorExit(liquidity, true);\\r\\n }\\r\\n\\r\\n /// @notice Claim all possible rewards.\\r\\n /// @return rewardTokens Claimed token addresses\\r\\n /// @return rewardAmounts Claimed token amounts\\r\\n /// @return depositorBalancesBefore Must have the same length as _depositorPoolAssets and represent balances before claim in the same order\\r\\n function _depositorClaimRewards() internal virtual returns (\\r\\n address[] memory rewardTokens,\\r\\n uint[] memory rewardAmounts,\\r\\n uint[] memory depositorBalancesBefore\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0xf268ae50022f5028f4717d1e0256447ce5f0c3f671080d400a436f19d182e57e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../ConverterStrategyBase.sol\\\";\\r\\nimport \\\"./UniswapV3Depositor.sol\\\";\\r\\nimport \\\"./UniswapV3ConverterStrategyLogicLib.sol\\\";\\r\\nimport \\\"../../libs/AppPlatforms.sol\\\";\\r\\nimport \\\"../../interfaces/IRebalancingV2Strategy.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\n/// @title Delta-neutral liquidity hedging converter fill-up/swap rebalancing strategy for UniswapV3\\r\\n/// @notice This strategy provides delta-neutral liquidity hedging for Uniswap V3 pools. It rebalances the liquidity\\r\\n/// by utilizing fill-up and swap methods depending on the range size of the liquidity provided.\\r\\n/// @author a17\\r\\ncontract UniswapV3ConverterStrategy is UniswapV3Depositor, ConverterStrategyBase, IRebalancingV2Strategy {\\r\\n\\r\\n //region ------------------------------------------------- Constants\\r\\n\\r\\n string public constant override NAME = \\\"UniswapV3 Converter Strategy\\\";\\r\\n string public constant override PLATFORM = AppPlatforms.UNIV3;\\r\\n string public constant override STRATEGY_VERSION = \\\"3.1.7\\\";\\r\\n\\r\\n //endregion ------------------------------------------------- Constants\\r\\n\\r\\n //region ------------------------------------------------- INIT\\r\\n\\r\\n /// @notice Initialize the strategy with the given parameters.\\r\\n /// @param controller_ The address of the controller.\\r\\n /// @param splitter_ The address of the splitter.\\r\\n /// @param converter_ The address of the converter.\\r\\n /// @param pool_ The address of the pool.\\r\\n /// @param tickRange_ The tick range for the liquidity position.\\r\\n /// @param rebalanceTickRange_ The tick range for rebalancing.\\r\\n /// @param fuseThresholds Price thresholds for tokens [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function init(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address converter_,\\r\\n address pool_,\\r\\n int24 tickRange_,\\r\\n int24 rebalanceTickRange_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external initializer {\\r\\n __ConverterStrategyBase_init(controller_, splitter_, converter_);\\r\\n UniswapV3ConverterStrategyLogicLib.initStrategyState(\\r\\n state,\\r\\n controller_,\\r\\n pool_,\\r\\n tickRange_,\\r\\n rebalanceTickRange_,\\r\\n ISplitter(splitter_).asset(),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n // setup specific name for UI\\r\\n StrategyLib2._changeStrategySpecificName(baseState, UniswapV3ConverterStrategyLogicLib.createSpecificName(state.pair));\\r\\n }\\r\\n //endregion ------------------------------------------------- INIT\\r\\n\\r\\n //region --------------------------------------------- OPERATOR ACTIONS\\r\\n\\r\\n /// @notice Manually set status of the fuse\\r\\n /// @param status See PairBasedStrategyLib.FuseStatus enum for possible values\\r\\n function setFuseStatus(uint status) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n PairBasedStrategyLib.setFuseStatus(state.pair.fuseAB, PairBasedStrategyLib.FuseStatus(status));\\r\\n }\\r\\n\\r\\n /// @notice Set thresholds for the fuse: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// Decimals 18. The thresholds are compared with prices from TetuConverter's price oracle.\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n /// @param values Price thresholds: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n function setFuseThresholds(uint[4] memory values) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n PairBasedStrategyLib.setFuseThresholds(state.pair.fuseAB, values);\\r\\n }\\r\\n\\r\\n /// @dev Set a dedicated contract for rewards for properly counting.\\r\\n /// It is safe to allow change it to operator - we suppose the contract only temporally store the last rewards.\\r\\n function setStrategyProfitHolder(address strategyProfitHolder) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n state.pair.strategyProfitHolder = strategyProfitHolder;\\r\\n }\\r\\n\\r\\n /// @notice Set withdrawDone value.\\r\\n /// When a fuse was triggered ON, all debts should be closed and asset should be converted to underlying.\\r\\n /// After completion of the conversion withdrawDone can be set to 1.\\r\\n /// So, {getFuseStatus} will return withdrawDone=1 and you will know, that withdraw is not required\\r\\n /// @param done 0 - full withdraw required, 1 - full withdraw was done\\r\\n function setWithdrawDone(uint done) external {\\r\\n StrategyLib2.onlyOperators(controller());\\r\\n state.pair.withdrawDone = done;\\r\\n }\\r\\n //endregion --------------------------------------------- OPERATOR ACTIONS\\r\\n\\r\\n //region --------------------------------------------- METRIC VIEWS\\r\\n\\r\\n /// @notice Check if the strategy is ready for hard work.\\r\\n /// @return A boolean indicating if the strategy is ready for hard work.\\r\\n function isReadyToHardWork() override external virtual view returns (bool) {\\r\\n return !needRebalance()\\r\\n && !_isFuseTriggeredOn()\\r\\n && UniswapV3ConverterStrategyLogicLib.isReadyToHardWork(state.pair, _csbs.converter);\\r\\n }\\r\\n\\r\\n /// @notice Check if the strategy needs rebalancing.\\r\\n /// @return A boolean indicating if {rebalanceNoSwaps} should be called.\\r\\n function needRebalance() public view override returns (bool) {\\r\\n return UniswapV3ConverterStrategyLogicLib.needStrategyRebalance(state.pair, _csbs.converter);\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, fuse-status-tokenB, withdrawDone, 4 thresholds of token A, 4 thresholds of token B]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState() external view override returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n return PairBasedStrategyLogicLib.getDefaultState(state.pair);\\r\\n }\\r\\n //endregion ---------------------------------------------- METRIC VIEWS\\r\\n\\r\\n //region--------------------------------------------- REBALANCE\\r\\n /// @notice Rebalance using borrow/repay only, no swaps\\r\\n /// @param checkNeedRebalance Revert if rebalance is not needed. Pass false to deposit after withdrawByAgg-iterations\\r\\n function rebalanceNoSwaps(bool checkNeedRebalance) external override {\\r\\n address _controller = controller();\\r\\n StrategyLib2.onlyOperators(_controller);\\r\\n\\r\\n (uint profitToCover, uint oldTotalAssets) = _rebalanceBefore();\\r\\n uint[] memory tokenAmounts = UniswapV3ConverterStrategyLogicLib.rebalanceNoSwaps(\\r\\n _csbs,\\r\\n state.pair,\\r\\n [address(_csbs.converter), address(AppLib._getLiquidator(_controller))],\\r\\n oldTotalAssets,\\r\\n profitToCover,\\r\\n baseState.splitter,\\r\\n checkNeedRebalance,\\r\\n liquidationThresholds\\r\\n );\\r\\n _rebalanceAfter(tokenAmounts);\\r\\n state.pair.lastRebalanceNoSwap = block.timestamp;\\r\\n }\\r\\n //endregion--------------------------------------------- REBALANCE\\r\\n\\r\\n //region --------------------------------------------- Withdraw by iterations\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n function quoteWithdrawByAgg(bytes memory planEntryData) external returns (address tokenToSwap, uint amountToSwap) {\\r\\n // restriction \\\"operator only\\\" is checked inside {initWithdrawLocal} in {quoteWithdrawStep}\\r\\n\\r\\n // estimate amounts to be withdrawn from the pool\\r\\n uint totalLiquidity = state.pair.totalLiquidity;\\r\\n uint[] memory amountsOut = (totalLiquidity == 0)\\r\\n ? new uint[](2)\\r\\n : _depositorQuoteExit(totalLiquidity);\\r\\n\\r\\n return PairBasedStrategyLogicLib.quoteWithdrawByAgg(\\r\\n state.pair,\\r\\n planEntryData,\\r\\n amountsOut,\\r\\n controller(),\\r\\n _csbs.converter,\\r\\n liquidationThresholds\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw iteration: [exit from the pool], [make 1 swap], [repay a debt], [enter to the pool]\\r\\n /// Typical sequence of the actions is: exit from the pool, make 1 swap, repay 1 debt.\\r\\n /// You can enter to the pool if you are sure that you won't have borrow + repay on AAVE3 in the same block.\\r\\n /// @dev All swap-by-agg data should be prepared using {quoteWithdrawByAgg} off-chain\\r\\n /// @param tokenToSwap_ What token should be swapped to other\\r\\n /// @param aggregator_ Aggregator that should be used on next swap. 0 - use liquidator\\r\\n /// @param amountToSwap_ Amount that should be swapped. 0 - no swap\\r\\n /// @param swapData Swap rote that was prepared off-chain.\\r\\n /// @param planEntryData PLAN_XXX + additional data, see IterationPlanKinds\\r\\n /// @param entryToPool Allow to enter to the pool at the end. Use false if you are going to make several iterations.\\r\\n /// It's possible to enter back to the pool by calling {rebalanceNoSwaps} at any moment\\r\\n /// 0 - not allowed, 1 - allowed, 2 - allowed only if completed\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions.\\r\\n function withdrawByAggStep(\\r\\n address tokenToSwap_,\\r\\n address aggregator_,\\r\\n uint amountToSwap_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n uint entryToPool\\r\\n ) external returns (bool completed) {\\r\\n // restriction \\\"operator only\\\" is checked inside UniswapV3ConverterStrategyLogicLib.withdrawByAggStep\\r\\n // fix price changes, exit from the pool\\r\\n (uint profitToCover, uint oldTotalAssets) = _rebalanceBefore();\\r\\n\\r\\n // check \\\"operator only\\\", make withdraw step, cover-loss, send profit to cover, prepare to enter to the pool\\r\\n uint[] memory tokenAmounts;\\r\\n\\r\\n (completed, tokenAmounts) = UniswapV3ConverterStrategyLogicLib.withdrawByAggStep(\\r\\n _csbs,\\r\\n [tokenToSwap_, aggregator_, controller(), address(_csbs.converter), baseState.splitter],\\r\\n [amountToSwap_, profitToCover, oldTotalAssets, entryToPool],\\r\\n swapData,\\r\\n planEntryData,\\r\\n state.pair,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // enter to the pool\\r\\n _rebalanceAfter(tokenAmounts);\\r\\n state.pair.lastRebalanceNoSwap = 0;\\r\\n\\r\\n if (completed && _isFuseTriggeredOn()) {\\r\\n // full withdraw was completed, we can exclude next calls of withdrawByAggStep\\r\\n state.pair.withdrawDone = 1;\\r\\n }\\r\\n\\r\\n ConverterStrategyBaseLib2.fixTooHighInvestedAssets(baseState.asset, oldTotalAssets, _csbs);\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view override returns (uint) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getPropNotUnderlying18(state.pair);\\r\\n }\\r\\n //endregion ------------------------------------ Withdraw by iterations\\r\\n\\r\\n //region--------------------------------------------- INTERNAL LOGIC\\r\\n\\r\\n function _beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint /*indexAsset_*/\\r\\n ) override internal virtual returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n if (needRebalance()) {\\r\\n // Rebalance is required, it's not allowed to enter to the pool\\r\\n // So let's return zero ready-to-invest amounts\\r\\n tokenAmounts = new uint[](2);\\r\\n } else {\\r\\n (uint prop0, uint prop1) = UniswapV3ConverterStrategyLogicLib.getEntryDataProportions(\\r\\n IUniswapV3Pool(state.pair.pool),\\r\\n state.pair.lowerTick,\\r\\n state.pair.upperTick,\\r\\n state.pair.depositorSwapTokens\\r\\n );\\r\\n\\r\\n // get token amounts for token A, token B\\r\\n address tokenA = state.pair.tokenA;\\r\\n tokenAmounts = PairBasedStrategyLogicLib._beforeDeposit(\\r\\n converter_,\\r\\n amount_,\\r\\n tokenA,\\r\\n state.pair.tokenB,\\r\\n prop0 * 1e18 / (prop0 + prop1),\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // take into account a possibility that tokens_ can contain [B, A]\\r\\n if (tokens_[0] != tokenA) {\\r\\n (tokenAmounts[0], tokenAmounts[1]) = (tokenAmounts[1], tokenAmounts[0]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards, do _processClaims() after claiming, calculate earned and lost amounts\\r\\n /// @return earned The amount of earned rewards\\r\\n /// @return lost The amount of lost rewards\\r\\n /// @return assetBalanceAfterClaim The asset balance after claiming rewards.\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Total performance fee in terms of underlying\\r\\n function _handleRewards() override internal virtual returns (\\r\\n uint earned,\\r\\n uint lost,\\r\\n uint assetBalanceAfterClaim,\\r\\n uint paidDebtToInsurance,\\r\\n uint amountPerf\\r\\n ) {\\r\\n (address[] memory rewardTokens, uint[] memory amounts) = _claim();\\r\\n address asset = baseState.asset;\\r\\n earned = UniswapV3ConverterStrategyLogicLib.calcEarned(asset, controller(), rewardTokens, amounts);\\r\\n (paidDebtToInsurance, amountPerf) = _rewardsLiquidation(rewardTokens, amounts);\\r\\n lost = 0; // hide warning\\r\\n assetBalanceAfterClaim = AppLib.balance(asset);\\r\\n }\\r\\n\\r\\n /// @notice Deposit given amount to the pool.\\r\\n /// @param amount_ The amount to be deposited.\\r\\n /// @param updateTotalAssetsBeforeInvest_ A boolean indicating if the total assets should be updated before investing.\\r\\n /// @return strategyLoss Loss should be covered from Insurance\\r\\n function _depositToPool(uint amount_, bool updateTotalAssetsBeforeInvest_) override internal virtual returns (\\r\\n uint strategyLoss\\r\\n ) {\\r\\n if (_isFuseTriggeredOn()) {\\r\\n uint[] memory tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = amount_;\\r\\n emit OnDepositorEnter(tokenAmounts, tokenAmounts);\\r\\n return 0;\\r\\n } else {\\r\\n return super._depositToPool(amount_, updateTotalAssetsBeforeInvest_);\\r\\n }\\r\\n }\\r\\n\\r\\n function _beforeWithdraw(uint /*amount*/) internal view override {\\r\\n // 3.1.7: try to allow withdraw when rebalance is needed\\r\\n // require(!needRebalance(), Uni3StrategyErrors.NEED_REBALANCE);\\r\\n }\\r\\n\\r\\n /// @notice Check need-rebalance and fuse-ON\\r\\n /// @return True if the hardwork should be skipped\\r\\n function _preHardWork(bool reInvest) internal view override returns (bool) {\\r\\n reInvest; // hide warning\\r\\n require(!needRebalance(), Uni3StrategyErrors.NEED_REBALANCE);\\r\\n require(!_isFuseTriggeredOn(), Uni3StrategyErrors.FUSE_IS_ACTIVE);\\r\\n return false;\\r\\n }\\r\\n\\r\\n /// @notice Prepare to rebalance: fix price changes, call depositor exit if totalLiquidity != 0\\r\\n function _rebalanceBefore() internal returns (uint profitToCover, uint oldTotalAssets) {\\r\\n (, profitToCover) = _fixPriceChanges(true);\\r\\n oldTotalAssets = totalAssets() - profitToCover;\\r\\n\\r\\n // withdraw all liquidity from pool\\r\\n // after disableFuse() liquidity is zero\\r\\n uint liquidity = state.pair.totalLiquidity;\\r\\n if (liquidity != 0) {\\r\\n _depositorExit(liquidity, false);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make actions after rebalance: depositor enter, update invested assets\\r\\n function _rebalanceAfter(uint[] memory tokenAmounts) internal {\\r\\n if (tokenAmounts.length == 2 && !_isFuseTriggeredOn()) {\\r\\n _depositorEnter(tokenAmounts);\\r\\n }\\r\\n _updateInvestedAssets();\\r\\n }\\r\\n\\r\\n function _isFuseTriggeredOn() internal view returns (bool) {\\r\\n return PairBasedStrategyLib.isFuseTriggeredOn(state.pair.fuseAB.status);\\r\\n }\\r\\n //endregion--------------------------------------- INTERNAL LOGIC\\r\\n}\\r\\n\",\"keccak256\":\"0x3a2ea5355c7e197f23de8dbf8530474b4b97dd91034718c0d8d6313e09964216\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./UniswapV3DebtLib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../../libs/AppErrors.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3ConverterStrategyLogicLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_STABLE = 300;\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE = 500;\\r\\n uint internal constant HARD_WORK_USD_FEE_THRESHOLD = 100;\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event Rebalanced(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event RebalancedDebt(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event UniV3FeesClaimed(uint fee0, uint fee1);\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n\\r\\n struct State {\\r\\n PairBasedStrategyLogicLib.PairState pair;\\r\\n // additional (specific) state\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[10] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceLocal {\\r\\n /// @notice Fuse for token A and token B\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n ITetuConverter converter;\\r\\n IUniswapV3Pool pool;\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool isStablePool;\\r\\n uint[2] liquidationThresholdsAB;\\r\\n\\r\\n bool fuseStatusChangedAB;\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB;\\r\\n\\r\\n uint poolPrice;\\r\\n uint poolPriceAdjustment;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Helpers\\r\\n\\r\\n /// @dev Gets the liquidator swap slippage based on the pool type (stable or volatile).\\r\\n /// @param pool The IUniswapV3Pool instance.\\r\\n /// @return The liquidator swap slippage percentage.\\r\\n function _getLiquidatorSwapSlippage(IUniswapV3Pool pool) internal view returns (uint) {\\r\\n return isStablePool(pool) ? LIQUIDATOR_SWAP_SLIPPAGE_STABLE : LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE;\\r\\n }\\r\\n\\r\\n /// @notice Check if the given pool is a stable pool.\\r\\n /// @param pool The Uniswap V3 pool.\\r\\n /// @return A boolean indicating if the pool is stable.\\r\\n function isStablePool(IUniswapV3Pool pool) public view returns (bool) {\\r\\n return pool.fee() == 100;\\r\\n }\\r\\n\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function initStrategyState(\\r\\n State storage state,\\r\\n address controller_,\\r\\n address pool,\\r\\n int24 tickRange,\\r\\n int24 rebalanceTickRange,\\r\\n address asset_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n require(pool != address(0), AppErrors.ZERO_ADDRESS);\\r\\n address token0 = IUniswapV3Pool(pool).token0();\\r\\n address token1 = IUniswapV3Pool(pool).token1();\\r\\n\\r\\n int24[4] memory tickData;\\r\\n {\\r\\n int24 tickSpacing = UniswapV3Lib.getTickSpacing(IUniswapV3Pool(pool).fee());\\r\\n if (tickRange != 0) {\\r\\n require(tickRange == tickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_TICK_RANGE);\\r\\n require(rebalanceTickRange == rebalanceTickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_REBALANCE_TICK_RANGE);\\r\\n }\\r\\n tickData[0] = tickSpacing;\\r\\n (tickData[1], tickData[2]) = UniswapV3DebtLib.calcTickRange(pool, tickRange, tickSpacing);\\r\\n tickData[3] = rebalanceTickRange;\\r\\n }\\r\\n\\r\\n PairBasedStrategyLogicLib.setInitialDepositorValues(\\r\\n state.pair,\\r\\n [pool, asset_, token0, token1],\\r\\n tickData,\\r\\n isStablePool(IUniswapV3Pool(pool)),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n address liquidator = IController(controller_).liquidator();\\r\\n IERC20(token0).approve(liquidator, type(uint).max);\\r\\n IERC20(token1).approve(liquidator, type(uint).max);\\r\\n }\\r\\n\\r\\n function createSpecificName(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (string memory) {\\r\\n return string(abi.encodePacked(\\r\\n \\\"UniV3 \\\",\\r\\n IERC20Metadata(pairState.tokenA).symbol(),\\r\\n \\\"/\\\",\\r\\n IERC20Metadata(pairState.tokenB).symbol(),\\r\\n \\\"-\\\",\\r\\n StringLib._toString(IUniswapV3Pool(pairState.pool).fee()))\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance.\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(IUniswapV3Pool pool, int24 lowerTick, int24 upperTick, bool depositorSwapTokens) external view returns (uint, uint) {\\r\\n return UniswapV3DebtLib.getEntryDataProportions(pool, lowerTick, upperTick, depositorSwapTokens);\\r\\n }\\r\\n //endregion ------------------------------------------------ Helpers\\r\\n\\r\\n //region ------------------------------------------------ Pool info\\r\\n /// @notice Retrieve the reserves of a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return reserves An array containing the reserve amounts of the contract owned liquidity.\\r\\n function getPoolReserves(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n uint[] memory reserves\\r\\n ) {\\r\\n reserves = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (reserves[0], reserves[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.totalLiquidity\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (reserves[0], reserves[1]) = (reserves[1], reserves[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return fee0 The fees generated for the first token in the pool.\\r\\n /// @return fee1 The fees generated for the second token in the pool.\\r\\n function getFees(PairBasedStrategyLogicLib.PairState storage pairState) public view returns (uint fee0, uint fee1) {\\r\\n UniswapV3Lib.PoolPosition memory position = UniswapV3Lib.PoolPosition(pairState.pool, pairState.lowerTick, pairState.upperTick, pairState.totalLiquidity, address(this));\\r\\n (fee0, fee1) = UniswapV3Lib.getFees(position);\\r\\n }\\r\\n\\r\\n /// @notice Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the estimated exit amounts for each token in the pool.\\r\\n function quoteExit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) public view returns (uint[] memory amountsOut) {\\r\\n amountsOut = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (amountsOut[0], amountsOut[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n liquidityAmountToExit\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Pool info\\r\\n\\r\\n //region ------------------------------------------------ Join the pool\\r\\n /// @notice Enter the pool and provide liquidity with desired token amounts.\\r\\n /// @param pool The Uniswap V3 pool to provide liquidity to.\\r\\n /// @param lowerTick The lower tick value for the pool.\\r\\n /// @param upperTick The upper tick value for the pool.\\r\\n /// @param amountsDesired_ An array containing the desired amounts of tokens to provide liquidity.\\r\\n /// @param totalLiquidity The current total liquidity in the pool.\\r\\n /// @param _depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return amountsConsumed An array containing the consumed amounts for each token in the pool.\\r\\n /// @return liquidityOut The amount of liquidity added to the pool.\\r\\n /// @return totalLiquidityNew The updated total liquidity after providing liquidity.\\r\\n function enter(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint[] memory amountsDesired_,\\r\\n uint128 totalLiquidity,\\r\\n bool _depositorSwapTokens\\r\\n ) external returns (uint[] memory amountsConsumed, uint liquidityOut, uint128 totalLiquidityNew) {\\r\\n amountsConsumed = new uint[](2);\\r\\n\\r\\n if (amountsDesired_[1] > 0) {\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsDesired_[0], amountsDesired_[1]) = (amountsDesired_[1], amountsDesired_[0]);\\r\\n }\\r\\n uint128 newLiquidity;\\r\\n (amountsConsumed[0], amountsConsumed[1], newLiquidity) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, amountsDesired_[0], amountsDesired_[1]);\\r\\n pool.mint(address(this), lowerTick, upperTick, newLiquidity, \\\"\\\");\\r\\n liquidityOut = uint(newLiquidity);\\r\\n totalLiquidityNew = totalLiquidity + newLiquidity;\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsConsumed[0], amountsConsumed[1]) = (amountsConsumed[1], amountsConsumed[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountsConsumed, liquidityOut, totalLiquidityNew);\\r\\n }\\r\\n\\r\\n //endregion ------------------------------------------------ Join the pool\\r\\n\\r\\n //region ------------------------------------------------ Exit from the pool\\r\\n /// @notice Exit the pool and collect tokens proportional to the liquidity amount to exit.\\r\\n /// @param pairState The State storage object.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the collected amounts for each token in the pool.\\r\\n function exit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) external returns (uint[] memory amountsOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n uint128 liquidity = pairState.totalLiquidity;\\r\\n bool _depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n\\r\\n require(liquidity >= liquidityAmountToExit, Uni3StrategyErrors.WRONG_LIQUIDITY);\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n (amountsOut[0], amountsOut[1]) = pool.burn(lowerTick, upperTick, liquidityAmountToExit);\\r\\n\\r\\n // all fees will be collected but not returned in amountsOut\\r\\n pool.collect(address(this), lowerTick, upperTick, type(uint128).max, type(uint128).max);\\r\\n\\r\\n pairState.totalLiquidity = liquidity - liquidityAmountToExit;\\r\\n\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Exit from the pool\\r\\n\\r\\n //region ------------------------------------------------ Claims\\r\\n /// @notice Claim rewards from the Uniswap V3 pool.\\r\\n /// @return tokensOut An array containing tokenA and tokenB.\\r\\n /// @return amountsOut An array containing the amounts of token0 and token1 claimed as rewards.\\r\\n function claimRewards(PairBasedStrategyLogicLib.PairState storage pairState) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n tokensOut = new address[](2);\\r\\n tokensOut[0] = pairState.tokenA;\\r\\n tokensOut[1] = pairState.tokenB;\\r\\n\\r\\n balancesBefore = new uint[](2);\\r\\n for (uint i; i < tokensOut.length; i++) {\\r\\n balancesBefore[i] = IERC20(tokensOut[i]).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n if (pairState.totalLiquidity > 0) {\\r\\n pool.burn(lowerTick, upperTick, 0);\\r\\n (amountsOut[0], amountsOut[1]) = pool.collect(\\r\\n address(this),\\r\\n lowerTick,\\r\\n upperTick,\\r\\n type(uint128).max,\\r\\n type(uint128).max\\r\\n );\\r\\n }\\r\\n\\r\\n emit UniV3FeesClaimed(amountsOut[0], amountsOut[1]);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n\\r\\n for (uint i; i < tokensOut.length; ++i) {\\r\\n uint b = IERC20(tokensOut[i]).balanceOf(strategyProfitHolder);\\r\\n if (b > 0) {\\r\\n IERC20(tokensOut[i]).transferFrom(strategyProfitHolder, address(this), b);\\r\\n amountsOut[i] += b;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n function isReadyToHardWork(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter) external view returns (\\r\\n bool isReady\\r\\n ) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n (uint fee0, uint fee1) = getFees(pairState);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (fee0, fee1) = (fee1, fee0);\\r\\n }\\r\\n\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n address h = pairState.strategyProfitHolder;\\r\\n\\r\\n fee0 += IERC20(tokenA).balanceOf(h);\\r\\n fee1 += IERC20(tokenB).balanceOf(h);\\r\\n\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n\\r\\n uint fee0USD = fee0 * priceA / 1e18;\\r\\n uint fee1USD = fee1 * priceB / 1e18;\\r\\n\\r\\n return fee0USD > HARD_WORK_USD_FEE_THRESHOLD || fee1USD > HARD_WORK_USD_FEE_THRESHOLD;\\r\\n }\\r\\n\\r\\n function sendFeeToProfitHolder(PairBasedStrategyLogicLib.PairState storage pairState, uint fee0, uint fee1) external {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n require(strategyProfitHolder != address (0), Uni3StrategyErrors.ZERO_PROFIT_HOLDER);\\r\\n if (pairState.depositorSwapTokens) {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee1);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee0);\\r\\n } else {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee0);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee1);\\r\\n }\\r\\n emit UniV3FeesClaimed(fee0, fee1);\\r\\n }\\r\\n\\r\\n function calcEarned(address asset, address controller, address[] memory rewardTokens, uint[] memory amounts) external view returns (uint) {\\r\\n ITetuLiquidator liquidator = ITetuLiquidator(IController(controller).liquidator());\\r\\n uint len = rewardTokens.length;\\r\\n uint earned;\\r\\n for (uint i; i < len; ++i) {\\r\\n address token = rewardTokens[i];\\r\\n if (token == asset) {\\r\\n earned += amounts[i];\\r\\n } else {\\r\\n earned += liquidator.getPrice(rewardTokens[i], asset, amounts[i]);\\r\\n }\\r\\n }\\r\\n\\r\\n return earned;\\r\\n }\\r\\n //endregion ------------------------------------------------ Claims\\r\\n\\r\\n //region ------------------------------------------------ Rebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter_) external view returns (\\r\\n bool needRebalance\\r\\n ) {\\r\\n address pool = pairState.pool;\\r\\n // poolPrice should have same decimals as a price from oracle == 18\\r\\n uint poolPriceAdjustment = PairBasedStrategyLib.getPoolPriceAdjustment(IERC20Metadata(pairState.tokenA).decimals());\\r\\n uint poolPrice = UniswapV3Lib.getPrice(pool, pairState.tokenB) * poolPriceAdjustment;\\r\\n (needRebalance, , ) = PairBasedStrategyLogicLib.needStrategyRebalance(\\r\\n pairState,\\r\\n converter_,\\r\\n UniswapV3DebtLib.getCurrentTick(IUniswapV3Pool(pool)),\\r\\n poolPrice\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make rebalance without swaps (using borrowing only).\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param totalAssets_ Current value of totalAssets()\\r\\n /// @param checkNeedRebalance_ True if the function should ensure that the rebalance is required\\r\\n /// @return tokenAmounts Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\\r\\n function rebalanceNoSwaps(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n address[2] calldata converterLiquidator,\\r\\n uint totalAssets_,\\r\\n uint profitToCover,\\r\\n address splitter,\\r\\n bool checkNeedRebalance_,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n RebalanceLocal memory v;\\r\\n _initLocalVars(v, ITetuConverter(converterLiquidator[0]), pairState, liquidityThresholds_);\\r\\n v.poolPrice = UniswapV3Lib.getPrice(address(v.pool), pairState.tokenB) * v.poolPriceAdjustment;\\r\\n bool needRebalance;\\r\\n int24 tick = UniswapV3DebtLib.getCurrentTick(v.pool);\\r\\n (needRebalance,v.fuseStatusChangedAB, v.fuseStatusAB) = PairBasedStrategyLogicLib.needStrategyRebalance(pairState, v.converter, tick, v.poolPrice);\\r\\n\\r\\n // update fuse status if necessary\\r\\n if (needRebalance) {\\r\\n // we assume here, that needRebalance is true if any fuse has changed state, see needStrategyRebalance impl\\r\\n PairBasedStrategyLogicLib.updateFuseStatus(pairState, v.fuseStatusChangedAB, v.fuseStatusAB);\\r\\n }\\r\\n\\r\\n require(!checkNeedRebalance_ || needRebalance, Uni3StrategyErrors.NO_REBALANCE_NEEDED);\\r\\n\\r\\n // rebalancing debt, setting new tick range\\r\\n if (needRebalance) {\\r\\n UniswapV3DebtLib.rebalanceNoSwaps(converterLiquidator, pairState, profitToCover, totalAssets_, splitter, v.liquidationThresholdsAB, tick);\\r\\n\\r\\n uint loss;\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(v.converter, totalAssets_, v.tokenA, v.tokenB, v.liquidationThresholdsAB);\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(csbs, splitter, loss);\\r\\n }\\r\\n emit Rebalanced(loss, profitToCover, 0);\\r\\n }\\r\\n\\r\\n return tokenAmounts;\\r\\n }\\r\\n\\r\\n /// @notice Initialize {v} by state values\\r\\n function _initLocalVars(\\r\\n RebalanceLocal memory v,\\r\\n ITetuConverter converter_,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) internal view {\\r\\n v.pool = IUniswapV3Pool(pairState.pool);\\r\\n v.fuseAB = pairState.fuseAB;\\r\\n v.converter = converter_;\\r\\n v.tokenA = pairState.tokenA;\\r\\n v.tokenB = pairState.tokenB;\\r\\n v.isStablePool = pairState.isStablePool;\\r\\n v.liquidationThresholdsAB[0] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenA]);\\r\\n v.liquidationThresholdsAB[1] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenB]);\\r\\n uint poolPriceDecimals = IERC20Metadata(v.tokenA).decimals();\\r\\n v.poolPriceAdjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n /// @notice Get proportion of not-underlying in the pool, [0...1e18]\\r\\n /// prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\\r\\n function getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage pairState) view external returns (uint) {\\r\\n // get pool proportions\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n bool depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n (int24 newLowerTick, int24 newUpperTick) = UniswapV3DebtLib._calcNewTickRange(pool, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint consumed0, uint consumed1) = UniswapV3DebtLib.getEntryDataProportions(pool, newLowerTick, newUpperTick, depositorSwapTokens);\\r\\n\\r\\n require(consumed0 + consumed1 > 0, AppErrors.ZERO_VALUE);\\r\\n return consumed1 * 1e18 / (consumed0 + consumed1);\\r\\n }\\r\\n //endregion ------------------------------------------------ Rebalance\\r\\n\\r\\n //region ------------------------------------------------ WithdrawByAgg\\r\\n /// @notice Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmountsOut Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\\r\\n function withdrawByAggStep(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint entryToPool = values_[3];\\r\\n address[2] memory tokens = [pairState.tokenA, pairState.tokenB];\\r\\n\\r\\n // Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n uint[] memory tokenAmounts;\\r\\n uint loss;\\r\\n (completed, tokenAmounts, loss) = PairBasedStrategyLogicLib.withdrawByAggStep(\\r\\n addr_,\\r\\n values_,\\r\\n swapData,\\r\\n planEntryData,\\r\\n tokens,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // cover loss\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(\\r\\n csbs,\\r\\n addr_[4],\\r\\n loss\\r\\n );\\r\\n }\\r\\n emit RebalancedDebt(loss, values_[1], 0);\\r\\n\\r\\n if (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED\\r\\n || (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED && completed)\\r\\n ) {\\r\\n // We are going to enter to the pool: update lowerTick and upperTick, initialize tokenAmountsOut\\r\\n (pairState.lowerTick, pairState.upperTick) = UniswapV3DebtLib._calcNewTickRange(\\r\\n IUniswapV3Pool(pairState.pool),\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing\\r\\n );\\r\\n tokenAmountsOut = tokenAmounts;\\r\\n }\\r\\n return (completed, tokenAmountsOut); // hide warning\\r\\n }\\r\\n //endregion ------------------------------------------------ WithdrawByAgg\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4430a5a110ff7a45e1cc8930b9ec640e7f97305de498cd5647290ee1f512fa31\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Depositor.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Initializable.sol\\\";\\r\\nimport \\\"../DepositorBase.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3MintCallback.sol\\\";\\r\\nimport \\\"./UniswapV3ConverterStrategyLogicLib.sol\\\";\\r\\n\\r\\n/// @title UniswapV3Depositor\\r\\n/// @dev Abstract contract that is designed to interact with Uniswap V3 pools and manage liquidity.\\r\\n/// Inherits from IUniswapV3MintCallback, DepositorBase, and Initializable.\\r\\nabstract contract UniswapV3Depositor is IUniswapV3MintCallback, DepositorBase, Initializable {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// CONSTANTS\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @dev Version of this contract. Adjust manually on each code modification.\\r\\n string public constant UNISWAPV3_DEPOSITOR_VERSION = \\\"1.0.4\\\";\\r\\n\\r\\n uint internal constant IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_A = 0;\\r\\n uint internal constant IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_B = 1;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// VARIABLES\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @dev State variable to store the current state of the whole strategy\\r\\n UniswapV3ConverterStrategyLogicLib.State internal state;\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[100 - 60] private __gap;\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// View\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @return nums Balances of [tokenA, tokenB] for profit holder\\r\\n function getSpecificState() external view returns (\\r\\n uint[] memory nums\\r\\n ) {\\r\\n address strategyProfitHolder = state.pair.strategyProfitHolder;\\r\\n nums = new uint[](2);\\r\\n nums[IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_A] = IERC20(state.pair.tokenA).balanceOf(strategyProfitHolder);\\r\\n nums[IDX_SS_NUMS_PROFIT_HOLDER_BALANCE_B] = IERC20(state.pair.tokenB).balanceOf(strategyProfitHolder);\\r\\n }\\r\\n\\r\\n /// @notice Returns the fees for the current state.\\r\\n /// @return fee0 and fee1.\\r\\n function getFees() public view returns (uint fee0, uint fee1) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getFees(state.pair);\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool assets.\\r\\n /// @return poolAssets An array containing the addresses of the pool assets.\\r\\n function _depositorPoolAssets() override internal virtual view returns (address[] memory poolAssets) {\\r\\n poolAssets = new address[](2);\\r\\n poolAssets[0] = state.pair.tokenA;\\r\\n poolAssets[1] = state.pair.tokenB;\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool weights and the total weight.\\r\\n /// @return weights An array containing the weights of the pool assets, and totalWeight the sum of the weights.\\r\\n function _depositorPoolWeights() override internal virtual view returns (uint[] memory weights, uint totalWeight) {\\r\\n weights = new uint[](2);\\r\\n weights[0] = 1;\\r\\n weights[1] = 1;\\r\\n totalWeight = 2;\\r\\n }\\r\\n\\r\\n /// @notice Returns the pool reserves.\\r\\n /// @return reserves An array containing the reserves of the pool assets.\\r\\n function _depositorPoolReserves() override internal virtual view returns (uint[] memory reserves) {\\r\\n return UniswapV3ConverterStrategyLogicLib.getPoolReserves(state.pair);\\r\\n }\\r\\n\\r\\n /// @notice Returns the current liquidity of the depositor.\\r\\n /// @return The current liquidity of the depositor.\\r\\n function _depositorLiquidity() override internal virtual view returns (uint) {\\r\\n return uint(state.pair.totalLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Returns the total supply of the depositor.\\r\\n /// @return In UniV3 we can not calculate the total supply of the whole pool. Return only ourself value.\\r\\n function _depositorTotalSupply() override internal view virtual returns (uint) {\\r\\n return uint(state.pair.totalLiquidity);\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// CALLBACK\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Callback function called by Uniswap V3 pool on mint operation.\\r\\n /// @param amount0Owed The amount of token0 owed to the pool.\\r\\n /// @param amount1Owed The amount of token1 owed to the pool.\\r\\n function uniswapV3MintCallback(\\r\\n uint amount0Owed,\\r\\n uint amount1Owed,\\r\\n bytes calldata /*_data*/\\r\\n ) external override {\\r\\n require(msg.sender == state.pair.pool, Uni3StrategyErrors.NOT_CALLBACK_CALLER);\\r\\n if (amount0Owed > 0) IERC20(state.pair.depositorSwapTokens ? state.pair.tokenB : state.pair.tokenA).safeTransfer(msg.sender, amount0Owed);\\r\\n if (amount1Owed > 0) IERC20(state.pair.depositorSwapTokens ? state.pair.tokenA : state.pair.tokenB).safeTransfer(msg.sender, amount1Owed);\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// Enter, exit\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Handles the deposit operation.\\r\\n function _depositorEnter(uint[] memory amountsDesired_) override internal virtual returns (\\r\\n uint[] memory amountsConsumed,\\r\\n uint liquidityOut\\r\\n ) {\\r\\n (amountsConsumed, liquidityOut, state.pair.totalLiquidity) = UniswapV3ConverterStrategyLogicLib.enter(\\r\\n IUniswapV3Pool(state.pair.pool),\\r\\n state.pair.lowerTick,\\r\\n state.pair.upperTick,\\r\\n amountsDesired_,\\r\\n state.pair.totalLiquidity,\\r\\n state.pair.depositorSwapTokens\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Handles the withdrawal operation.\\r\\n /// @param liquidityAmount The amount of liquidity to be withdrawn.\\r\\n /// @param emergency Emergency exit (only withdraw, don't claim any rewards or make any other additional actions)\\r\\n /// @return amountsOut The amounts of the tokens withdrawn.\\r\\n function _depositorExit(uint liquidityAmount, bool emergency) override internal virtual returns (uint[] memory amountsOut) {\\r\\n uint fee0;\\r\\n uint fee1;\\r\\n if (! emergency) {\\r\\n (fee0, fee1) = getFees();\\r\\n }\\r\\n amountsOut = UniswapV3ConverterStrategyLogicLib.exit(state.pair, uint128(liquidityAmount));\\r\\n if (! emergency) {\\r\\n UniswapV3ConverterStrategyLogicLib.sendFeeToProfitHolder(state.pair, fee0, fee1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the amount of tokens that would be withdrawn based on the provided liquidity amount.\\r\\n /// @param liquidityAmount The amount of liquidity to quote the withdrawal for.\\r\\n /// @return amountsOut The amounts of the tokens that would be withdrawn, underlying is first\\r\\n function _depositorQuoteExit(uint liquidityAmount) override internal virtual returns (uint[] memory amountsOut) {\\r\\n amountsOut = UniswapV3ConverterStrategyLogicLib.quoteExit(state.pair, uint128(liquidityAmount));\\r\\n }\\r\\n\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n /// Claim rewards\\r\\n /////////////////////////////////////////////////////////////////////\\r\\n\\r\\n /// @notice Claims all possible rewards.\\r\\n /// @return tokensOut An array containing the addresses of the reward tokens,\\r\\n /// @return amountsOut An array containing the amounts of the reward tokens.\\r\\n function _depositorClaimRewards() override internal virtual returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n (tokensOut, amountsOut, balancesBefore) = UniswapV3ConverterStrategyLogicLib.claimRewards(state.pair);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x8820cb9102960e222a4bcc12e83e77505c6f7b97cf70670466e5d5b51b9d52a0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615bed80620000f36000396000f3fe608060405234801561001057600080fd5b50600436106103645760003560e01c806371ee0175116101c9578063b429afeb116100ff578063d3487997116100ad578063dfeb10321161007c578063dfeb103214610795578063e50df07d146107a8578063f77c4791146107bb578063ffb86c6a146107c357600080fd5b8063d348799714610754578063db8d55f114610767578063de3d047c1461076f578063dee1f0e41461078257600080fd5b8063b429afeb146106b9578063b77c975b146106cc578063bd38837b146106fe578063cd4c81561461070f578063ce2f184214610720578063ceee861d14610728578063d295ea701461074c57600080fd5b806387c7f770116101775780639d0bcca0116101465780639d0bcca01461065a578063a3f4df7e14610662578063ab9e3eee1461069e578063b2457556146106a657600080fd5b806387c7f77014610610578063936725ec1461058257806396b7b14e14610623578063996a6c9c1461063657600080fd5b806371ee01751461057a57806373a50ef51461058257806378327438146105a65780637cc96380146105c65780637eba7ba6146105ce5780637efc77fa146105e0578063877887821461060857600080fd5b80634ba31b011161029e578063546799631161024c57806363e277341161021b57806363e277341461052e5780636b5fba5a146105415780636ffb4c8e146105545780637063a2371461056757600080fd5b806354679963146104e35780635641ec03146104f85780635cfc1a51146105005780636207a0cf1461050a57600080fd5b80634ba31b01146104635780634e71d92d1461046b5780634fa5d854146104735780634fac6ccd1461049057806351e03fbe146104a357806352bbbb74146104b65780635412335d146104cb57600080fd5b8063261efa12116103165780633cd8045e116102e55780633cd8045e1461042f57806342fdb471146104405780634593144c146104535780634ad0b6841461045b57600080fd5b8063261efa12146103fd578063325a19f11461040557806333c5b58e1461040d57806338d52e0f1461041557600080fd5b806301e1d1141461036957806301ffc9a714610384578063066a6fc3146103a75780630acd12c7146103ba5780630e30428d146103c25780631d2dca9e146103d75780632221eb3c146103ea575b600080fd5b6103716107cb565b6040519081526020015b60405180910390f35b6103976103923660046147ef565b610856565b604051901515815260200161037b565b6103976103b53660046148f1565b61089c565b610371610a7b565b6103d56103d036600461498b565b610b9d565b005b6103d56103e53660046149c5565b610c41565b6103d56103f83660046149e2565b610daa565b606854610371565b610371610e20565b610371610e50565b6064546001600160a01b03165b60405161037b91906149fb565b6065546001600160a01b0316610422565b6103d561044e3660046149e2565b610ed0565b610371610fbf565b609754610371565b610371610fef565b6103d5611066565b61047b6110e0565b6040805192835260208301919091520161037b565b6103d561049e366004614a0f565b61114e565b6103716104b13660046149e2565b611280565b6104be611448565b60405161037b9190614a67565b6104d3611598565b60405161037b9493929190614aac565b6104eb611627565b60405161037b9190614ba0565b6103d56116bc565b600160ff1b610371565b6104eb60405180604001604052806005815260200164332e312e3760d81b81525081565b6103d561053c366004614bf4565b611755565b6103d561054f366004614a0f565b611833565b6103d56105623660046149e2565b6118c4565b6103d5610575366004614c29565b61194c565b609954610371565b6104eb60405180604001604052806005815260200164332e302e3160d81b81525081565b6103716105b4366004614a0f565b60966020526000908152604090205481565b6103716119ea565b6103716105dc3660046149e2565b5490565b6104eb60405180604001604052806009815260200168556e6973776170563360b81b81525081565b606754610371565b61037161061e36600461498b565b611a1a565b6103d5610631366004614cea565b611d00565b6104eb604051806040016040528060058152602001640c4b8c0b8d60da1b81525081565b610422611da5565b6104eb6040518060400160405280601c81526020017f556e6973776170563320436f6e7665727465722053747261746567790000000081525081565b610397611dd5565b6103716106b4366004614dab565b611e80565b6103976106c7366004614a0f565b611f2f565b6106df6106da366004614ddb565b611f54565b604080516001600160a01b03909316835260208301919091520161037b565b6098546001600160a01b0316610422565b6066546001600160a01b0316610422565b609a54610371565b6104eb60405180604001604052806005815260200164199718971b60d91b81525081565b606954610371565b6103d5610762366004614e0f565b612046565b61047b612137565b6103d561077d3660046149e2565b6121af565b610397610790366004614a0f565b61220c565b6103d56107a3366004614e61565b612291565b6103d56107b6366004614eed565b612339565b61042261260d565b61039761263d565b60006107d660975490565b6064546040516370a0823160e01b81526001600160a01b03909116906370a08231906108069030906004016149fb565b602060405180830381865afa158015610823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108479190614f89565b6108519190614fb8565b905090565b60006001600160e01b03198216631e94dddf60e01b148061088757506001600160e01b0319821663f73147b360e01b145b8061089657506108968261268b565b92915050565b60008060006108a96126b0565b915091506060734B890495ae196454A8058aA4768bd5f3EE089bEE63911ec05360976040518060a001604052808e6001600160a01b03166001600160a01b031681526020018d6001600160a01b03166001600160a01b0316815260200161090e61260d565b6001600160a01b039081168252609854811660208084019190915260655490911660409283015281516080810183528e8152908101899052808201889052606081018b905290516001600160e01b031960e086901b16815261097f939291908d908d90600190609690600401614fee565b600060405180830381865af415801561099c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c491908101906150d2565b90945090506109d281612702565b60006010558380156109e757506109e7612731565b156109f2576001600f555b606480546040516368f9467b60e01b81526001600160a01b039091166004820152602481018490526097604482015273C92346a144fa75b45b0eDAe966FEAA0E30C82c55916368f9467b910160006040518083038186803b158015610a5657600080fd5b505af4158015610a6a573d6000803e3d6000fd5b505050505050509695505050505050565b606554606454604051633e53813360e11b81526000926001600160a01b0390811692169083907306c875daA1Dc2E27dd7381EB3b6be4F99553a60990637ca7026690610acd9086908690600401615118565b602060405180830381865af4158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190614f89565b90506000806000610b1d612743565b9250925092507306c875daA1Dc2E27dd7381EB3b6be4F99553a609639ad00ec2868686868b6040518663ffffffff1660e01b8152600401610b62959493929190615132565b60006040518083038186803b158015610b7a57600080fd5b505af4158015610b8e573d6000803e3d6000fd5b50929998505050505050505050565b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563142395ef610bbf61260d565b6040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290851660248201526044810184905260640160006040518083038186803b158015610c0d57600080fd5b505af4158015610c21573d6000803e3d6000fd5b5050506001600160a01b0390921660009081526096602052604090205550565b6000610c4b61260d565b60405163124fdbb760e21b81529091507306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063493f6edc90610c859084906004016149fb565b60006040518083038186803b158015610c9d57600080fd5b505af4158015610cb1573d6000803e3d6000fd5b50505050600080610cc06126b0565b604080518082019091526098546001600160a01b031681529193509150600090734B890495ae196454A8058aA4768bd5f3EE089bEE9063b6fda8139060979060019060208101610d0f8a61275e565b6001600160a01b039081169091526065546040516001600160e01b031960e088901b168152610d4f959493928a928c929116908e90609690600401615162565b600060405180830381865af4158015610d6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d9491908101906151db565b9050610d9f81612702565b505042601055505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610dcc61260d565b6040518263ffffffff1660e01b8152600401610de891906149fb565b60006040518083038186803b158015610e0057600080fd5b505af4158015610e14573d6000803e3d6000fd5b505050600f9190915550565b60006108516105dc60017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b61520f565b60007306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610e7461260d565b6040518263ffffffff1660e01b8152600401610e9091906149fb565b60006040518083038186803b158015610ea857600080fd5b505af4158015610ebc573d6000803e3d6000fd5b50505050610ec86127c2565b509092915050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc610ef261260d565b6040518263ffffffff1660e01b8152600401610f0e91906149fb565b60006040518083038186803b158015610f2657600080fd5b505af4158015610f3a573d6000803e3d6000fd5b5073E0D8b85C7Feb11b26e5A2466931088eC5DE7A7039250636bffb346915060069050836003811115610f6f57610f6f615222565b6040518363ffffffff1660e01b8152600401610f8c929190615238565b60006040518083038186803b158015610fa457600080fd5b505af4158015610fb8573d6000803e3d6000fd5b5050505050565b60006108516105dc60017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f161520f565b604051630a3c2bb160e21b815260016004820152600090734B890495ae196454A8058aA4768bd5f3EE089bEE906328f0aec490602401602060405180830381865af4158015611042573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108519190614f89565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963d19cc38a61108861260d565b6040518263ffffffff1660e01b81526004016110a491906149fb565b60006040518083038186803b1580156110bc57600080fd5b505af41580156110d0573d6000803e3d6000fd5b505050506110dc612893565b5050565b60655460408051808201909152600a81526914d08e8811195b9a595960b21b60208201526000918291906001600160a01b0316331461113b5760405162461bcd60e51b81526004016111329190614ba0565b60405180910390fd5b50611146600161294f565b915091509091565b33301461119d5760405162461bcd60e51b815260206004820152601b60248201527f496e637265617365207265766973696f6e20666f7262696464656e00000000006044820152606401611132565b60006111cd6105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b6111d8906001614fb8565b905061120c8161120960017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b55565b61123b8261120960017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e461520f565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c8910160405180910390a15050565b606554606454604051633e53813360e11b81526000926001600160a01b0390811692169083907306c875daA1Dc2E27dd7381EB3b6be4F99553a60990637ca70266906112d29086908690600401615118565b602060405180830381865af41580156112ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113139190614f89565b9050808511156113bf5760008061133261132d848961520f565b612b41565b604051631594b05b60e01b815290985091935091507306c875daA1Dc2E27dd7381EB3b6be4F99553a60990631594b05b906113799087908790879087908c90600401615132565b602060405180830381865af4158015611396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ba9190614f89565b925050505b6040516333bbb20360e11b815260048101869052602481018290526001600160a01b038084166044830152841660648201527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099063677764069060840160006040518083038186803b15801561142857600080fd5b505af415801561143c573d6000803e3d6000fd5b50505050505050919050565b600280546040805183815260608082018352936001600160a01b0390931692909160208301908036833750506003546040516370a0823160e01b81529294506001600160a01b0316916370a0823191506114a69084906004016149fb565b602060405180830381865afa1580156114c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190614f89565b826000815181106114fa576114fa61526a565b6020908102919091010152600480546040516370a0823160e01b81526001600160a01b03909116916370a0823191611534918591016149fb565b602060405180830381865afa158015611551573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614f89565b826001815181106115885761158861526a565b6020026020010181815250505090565b604051636e81b62960e01b8152600160048201526060908190819081907306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe3990636e81b62990602401600060405180830381865af41580156115f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116199190810190615348565b935093509350935090919293565b60606064600601805461163990615452565b80601f016020809104026020016040519081016040528092919081815260200182805461166590615452565b80156116b25780601f10611687576101008083540402835291602001916116b2565b820191906000526020600020905b81548152906001019060200180831161169557829003601f168201915b5050505050905090565b6116c4612b72565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963bd0206826116e661260d565b6064805460655460405160e086901b6001600160e01b03191681526001600160a01b03948516600482015291841660248301529290921660448301520160006040518083038186803b15801561173b57600080fd5b505af415801561174f573d6000803e3d6000fd5b50505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc61177761260d565b6040518263ffffffff1660e01b815260040161179391906149fb565b60006040518083038186803b1580156117ab57600080fd5b505af41580156117bf573d6000803e3d6000fd5b5050604051637fc1c15b60e01b81527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099250637fc1c15b91506117ff906064908690869060040161548c565b60006040518083038186803b15801561181757600080fd5b505af415801561182b573d6000803e3d6000fd5b505050505050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc61185561260d565b6040518263ffffffff1660e01b815260040161187191906149fb565b60006040518083038186803b15801561188957600080fd5b505af415801561189d573d6000803e3d6000fd5b5050600280546001600160a01b0319166001600160a01b0394909416939093179092555050565b73C92346a144fa75b45b0eDAe966FEAA0E30C82c5563d2c3cf256118e661260d565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024810184905260440160006040518083038186803b15801561192c57600080fd5b505af4158015611940573d6000803e3d6000fd5b50505060999190915550565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963ed6b63c1606485858561197361260d565b6040516001600160e01b031960e088901b168152600481019590955260248501939093526001600160a01b039182166044850152606484015216608482015260a40160006040518083038186803b1580156119cd57600080fd5b505af41580156119e1573d6000803e3d6000fd5b50505050505050565b60006108516105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b6000611a246147a7565b611a3084826000612bbd565b805160408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611a7c5760405162461bcd60e51b81526004016111329190614ba0565b5060408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015283611ac25760405162461bcd60e51b81526004016111329190614ba0565b5060001981606001511415604051806040016040528060118152602001701514cb4c4d081ddc9bdb99c8185cdcd95d607a1b81525090611b155760405162461bcd60e51b81526004016111329190614ba0565b50600080611b236001612c37565b608085015160405163513cfdb360e11b81526001600160a01b038a16600482015260248101919091526044810183905260648181018390526084820152919350915073C92346a144fa75b45b0eDAe966FEAA0E30C82c559063a279fb669060a401602060405180830381865af4158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc59190614f89565b60808401526000620186a0611bdc6103e882614fb8565b611be690886154c2565b611bf091906154d9565b905080846080015110611c1c578351611c14906001600160a01b0389169088612d01565b859450611ced565b82600003611c5757611c336103e8620186a0614fb8565b620186a08560800151611c4691906154c2565b611c5091906154d9565b9450611ced565b6000620186a0611c6a6103e860026154c2565b611c7790620186a0614fb8565b611c8190896154c2565b611c8b91906154d9565b9050611ca6856080015182611ca0919061520f565b86612d53565b506000611cb289612fb8565b9050828111611ce657611cca6103e8620186a0614fb8565b611cd7620186a0836154c2565b611ce191906154d9565b611ce8565b875b965050505b611cf5613028565b505050505092915050565b60985460408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611d4d5760405162461bcd60e51b81526004016111329190614ba0565b5080518251146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090611d975760405162461bcd60e51b81526004016111329190614ba0565b50611da0613028565b505050565b60006108516105dc60017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e461520f565b6000611ddf61263d565b158015611df15750611def612731565b155b8015610851575060985460405163119aa29360e11b8152600160048201526001600160a01b039091166024820152734B890495ae196454A8058aA4768bd5f3EE089bEE906323354526906044015b602060405180830381865af4158015611e5c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085191906154fb565b6065546064546040516001625acc3160e01b0319815260009283927306c875daA1Dc2E27dd7381EB3b6be4F99553a6099263ffa533cf92611ed2926001600160a01b0391821692911690600401615118565b602060405180830381865af4158015611eef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f139190614f89565b90508015611f2857611f25818461303e565b91505b5092915050565b6000611f3961260d565b6001600160a01b0316826001600160a01b0316149050919050565b6005546000908190630100000090046001600160801b0316818115611f8157611f7c826130e2565b611f9f565b60408051600280825260608201835290916020830190803683375050505b90507306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe396350d2e0ba60018784611fc761260d565b6098546040516001600160e01b031960e088901b168152611ffb95949392916001600160a01b031690609690600401615518565b6040805180830381865af4158015612017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203b9190615569565b935093505050915091565b60015460408051808201909152601a81527f5533532d3131204e6f742063616c6c6261636b2063616c6c65720000000000006020820152906001600160a01b031633146120a65760405162461bcd60e51b81526004016111329190614ba0565b5083156120f4576004546120f49033908690600160a81b900460ff166120d7576003546001600160a01b03166120e4565b6004546001600160a01b03165b6001600160a01b03169190612d01565b821561174f5760045461174f9033908590600160a81b900460ff16612124576004546001600160a01b03166120e4565b6003546001600160a01b03169190612d01565b604051630ba4ccab60e11b8152600160048201526000908190734B890495ae196454A8058aA4768bd5f3EE089bEE906317499956906024016040805180830381865af415801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111469190615597565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a609636d51f04360646121d361260d565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260448101849052606401610f8c565b6000816001600160a01b031661222061260d565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa15801561225d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228191906155bb565b6001600160a01b03161492915050565b7306c875daA1Dc2E27dd7381EB3b6be4F99553a60963493f6edc6122b361260d565b6040518263ffffffff1660e01b81526004016122cf91906149fb565b60006040518083038186803b1580156122e757600080fd5b505af41580156122fb573d6000803e3d6000fd5b5050604051630593c4c960e01b815273E0D8b85C7Feb11b26e5A2466931088eC5DE7A7039250630593c4c99150610f8c9060069085906004016155d8565b600054610100900460ff16158080156123595750600054600160ff909116105b806123735750303b158015612373575060005460ff166001145b6123d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611132565b6000805460ff1916600117905580156123f9576000805461ff0019166101001790555b61240488888861316c565b734B890495ae196454A8058aA4768bd5f3EE089bEE63adc4343460018a8888888d6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612462573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248691906155bb565b896040518863ffffffff1660e01b81526004016124a997969594939291906155ec565b60006040518083038186803b1580156124c157600080fd5b505af41580156124d5573d6000803e3d6000fd5b505060405163bd85be2960e01b8152600160048201527306c875daA1Dc2E27dd7381EB3b6be4F99553a6099250637fc1c15b9150606490734B890495ae196454A8058aA4768bd5f3EE089bEE9063bd85be2990602401600060405180830381865af4158015612548573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612570919081019061563d565b6040518363ffffffff1660e01b815260040161258d9291906156b3565b60006040518083038186803b1580156125a557600080fd5b505af41580156125b9573d6000803e3d6000fd5b505050508015612603576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60006108516105dc60017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c361861520f565b609854604051633934e59d60e11b8152600160048201526001600160a01b039091166024820152600090734B890495ae196454A8058aA4768bd5f3EE089bEE90637269cb3a90604401611e3f565b60006001600160e01b0319821663c19fa56160e01b148061089657506108968261320e565b6000806126bd6001612c37565b92508290506126ca6107cb565b6126d4919061520f565b600554909150630100000090046001600160801b031680156126fd576126fb816000613243565b505b509091565b805160021480156127185750612716612731565b155b156127295761272681613363565b50505b6110dc613028565b6006546000906108519060ff1661346b565b6000806000612753600019612b41565b925092509250909192565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561279e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089691906155bb565b6064546000906060908190839081906127e3906001600160a01b0316613488565b9150915073C92346a144fa75b45b0eDAe966FEAA0E30C82c55637325f33f8361280b856134f4565b6098546040516001600160e01b031960e086901b16815261284193929187916001600160a01b0390911690600190600401615705565b600060405180830381865af415801561285e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128869190810190615753565b9450945094505050909192565b60608060008060006128a3613573565b609854929550909350915073C92346a144fa75b45b0eDAe966FEAA0E30C82c559063e99de4da906001600160a01b03166128db6135fe565b8686866040518663ffffffff1660e01b81526004016128fe9594939291906157bf565b600060405180830381865af415801561291b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129439190810190615829565b90969095509350505050565b60008060008061295f6001612c37565b9150915061296c85613692565b612abf576000806000806000612980613747565b9450945094509450945060006129946127c2565b5050905060008060006129e78e80156129ac57508415155b80156129d35750609954620186a0906129c69087906154c2565b6129d091906154d9565b88115b6129de5760006129e0565b875b8b8661381a565b93509350935050612a1787856129fd9190614fb8565b84612a088486614fb8565b612a129190614fb8565b613a59565b909d509b50612a299250613a89915050565b604080518981526020810189905290810187905260608101869052608081018b905260a081018a905260c0810184905260e081018390527ff87a9dead982c86370b885093f79ded2c9a614d95d83c0c20f68e13e3b9b7d3f906101000160405180910390a1612aaa612a9b878c614fb8565b612aa58486614fb8565b613a8b565b9950612ab6858a614fb8565b98505050505050505b6098546064546040516323c1ae5960e11b815273C92346a144fa75b45b0eDAe966FEAA0E30C82c55926347835cb292612b0a926001600160a01b039283169290911690600401615118565b60006040518083038186803b158015612b2257600080fd5b505af4158015612b36573d6000803e3d6000fd5b505050505050915091565b6000806000806000612b536001612c37565b91509150612b62868284613aa5565b5091989097509095509350505050565b6000612b7c613ca9565b90507f768a28cb3459382a3d2173feb2dad0235f8de680b109872da581a3aa269fe5f481604051612bad9190614a67565b60405180910390a16110dc613028565b612bc56135fe565b604083018190526001600160a01b038085166020850152609854168352612bec9084613d30565b6060830152612bfa83612fb8565b608083015280612c24576040820151606454612c1f91906001600160a01b0316613d30565b612c2a565b81606001515b60a0909201919091525050565b6000808215612cf4576064546000908190612c5a906001600160a01b0316613488565b9150915073C92346a144fa75b45b0eDAe966FEAA0E30C82c55633643611860976064612c85866134f4565b86866040518663ffffffff1660e01b8152600401612ca7959493929190615882565b6040805180830381865af4158015612cc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce79190615597565b9094509250612cfc915050565b505060975460005b915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611da0908490613d8e565b600080612d706005546001600160801b0363010000009091041690565b90506000612d7d826130e2565b9050600073C92346a144fa75b45b0eDAe966FEAA0E30C82c55630252e2c78787604001518860600151896000015187898c60a001516040518863ffffffff1660e01b8152600401612dd497969594939291906158c6565b602060405180830381865af4158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e159190614f89565b90508015612e87576000612e2a826000613243565b600554909150630100000090046001600160801b0316612e4a908561520f565b91507faebc771af58936b05e89b0be7d3f9761480181abcd4a649fbdd01753fda169708282604051612e7d92919061591e565b60405180910390a1505b6000732af59Be93d77B391Fea20322407fE46907Bf9D0E63c432aee1876040015188606001518960000151612ec2612ebd61260d565b61275e565b6000198d14612ee0578c8c60800151612edb9190614fb8565b612ee2565b8c5b60966040518763ffffffff1660e01b8152600401612f0596959493929190615937565b602060405180830381865af4158015612f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f469190614f89565b905085608001518110156040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b81525090612f9d5760405162461bcd60e51b81526004016111329190614ba0565b506080860151612fad908261520f565b979650505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190612fe79030906004016149fb565b602060405180830381865afa158015613004573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190614f89565b60006130326127c2565b50506097819055919050565b6000613048612731565b156130d15760408051600280825260608201835260009260208301908036833701905050905083816000815181106130825761308261526a565b6020026020010181815250507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d0581826040516130bf92919061597a565b60405180910390a16000915050610896565b6130db8383613e60565b9050610896565b60405163a7aced0960e01b8152600160048201526001600160801b0382166024820152606090734B890495ae196454A8058aA4768bd5f3EE089bEE9063a7aced0990604401600060405180830381865af4158015613144573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261089691908101906151db565b600054610100900460ff166131935760405162461bcd60e51b81526004016111329061599f565b61319d8383613e8a565b609880546001600160a01b0319166001600160a01b0383161790556131c66064620186a06154d9565b6099557fe4166dfcf23bbd3e3f764a99dc8fa740554c03c82d6019b81cf265f396f6f2fe6131f86064620186a06154d9565b60405190815260200160405180910390a1505050565b60006001600160e01b0319821663b7b79fa960e01b148061089657506301ffc9a760e01b6001600160e01b0319831614610896565b60606000808361325b57613255612137565b90925090505b604051633ae60bcb60e01b8152600160048201526001600160801b0386166024820152734B890495ae196454A8058aA4768bd5f3EE089bEE90633ae60bcb90604401600060405180830381865af41580156132ba573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132e291908101906151db565b92508361335b57604051632b25a6cf60e01b8152600160048201526024810183905260448101829052734B890495ae196454A8058aA4768bd5f3EE089bEE90632b25a6cf9060640160006040518083038186803b15801561334257600080fd5b505af4158015613356573d6000803e3d6000fd5b505050505b505092915050565b60015460048054600554604051638008936760e01b8152606094600094734B890495ae196454A8058aA4768bd5f3EE089bEE946380089367946133e9946001600160a01b0390941693600160c81b8304600290810b94600160e01b850490910b938c93630100000090046001600160801b031692600160a81b90910460ff1691016159ea565b600060405180830381865af4158015613406573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261342e9190810190615a40565b600580546001600160801b0390921663010000000272ffffffffffffffffffffffffffffffff000000199092169190911790559094909350915050565b6000600182600381111561348157613481615222565b1192915050565b606060006134946135fe565b91506134a08284613d30565b90506000198114156040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906134ee5760405162461bcd60e51b81526004016111329190614ba0565b50915091565b606060006135126005546001600160801b0363010000009091041690565b9050801561352857613523816130e2565b61356c565b82516001600160401b038111156135415761354161482e565b60405190808252806020026020018201604052801561356a578160200160208202803683370190505b505b9392505050565b60405163af31673360e01b81526001600482015260609081908190734B890495ae196454A8058aA4768bd5f3EE089bEE9063af31673390602401600060405180830381865af41580156135ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135f29190810190615aa6565b91959094509092509050565b6040805160028082526060808301845292602083019080368337505060035482519293506001600160a01b03169183915060009061363e5761363e61526a565b6001600160a01b03928316602091820292909201015260045482519116908290600190811061366f5761366f61526a565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b600061369c61263d565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906136e85760405162461bcd60e51b81526004016111329190614ba0565b506136f1612731565b15604051806040016040528060158152602001745533532d313420467573652069732061637469766560581b8152509061373e5760405162461bcd60e51b81526004016111329190614ba0565b50600092915050565b600080600080600080600061375a612893565b60645491935091506001600160a01b0316734B890495ae196454A8058aA4768bd5f3EE089bEE6334d2ec3d8261378e61260d565b86866040518563ffffffff1660e01b81526004016137af9493929190615af4565b602060405180830381865af41580156137cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f09190614f89565b97506137fc8383613f33565b60009850909550935061380e81612fb8565b95505050509091929394565b6064546000908190819081906001600160a01b03168187891161383e576000613848565b613848888a61520f565b90506000620186a08860976002015461386191906154c2565b61386b91906154d9565b82119050600061387a84612fb8565b6001600160a01b03851660009081526096602052604090205490915061389f90613fde565b8a111561398e5781806138b25750898110155b1561397a5760655473C92346a144fa75b45b0eDAe966FEAA0E30C82c559063890ffb849086908d906001600160a01b03166138ed868f614fb8565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084810184905260a4016040805180830381865af415801561394e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139729190615597565b50965061398e565b61398660008b8b613aa5565b909a50985050505b8115613a1c576000806139a086613488565b60985491935091506000906139c0906001600160a01b0316878585613ff6565b90506139cb8161428c565b613a185760006139da82613363565b5090507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d058282604051613a0e92919061597a565b60405180910390a1505b5050505b613a24613028565b9550613a2f84612fb8565b9450613a49613a3e828b614fb8565b88612a08888a614fb8565b9850505050505093509350935093565b60008083831115613a7557613a6e848461520f565b9150613a82565b613a7f838561520f565b90505b9250929050565b565b6000818311613a9b57600061356c565b61356c828461520f565b60008060008060006000198814613ae957620186a0613ac66103e882614fb8565b613ad0898b614fb8565b613ada91906154c2565b613ae491906154d9565b613aeb565b875b90508015801590613afb57508515155b15613c9f57613b086147a7565b606454613b20906001600160a01b0316826001612bbd565b80516020820151604051637a55caf360e01b815273C92346a144fa75b45b0eDAe966FEAA0E30C82c5592637a55caf392613b5c92600401615118565b602060405180830381865af4158015613b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9d9190614f89565b9450670de0b6b3a764000085613bbc613bb68585612d53565b8b613a8b565b613bc691906154c2565b613bd091906154d9565b6065546020830151608084015192985073C92346a144fa75b45b0eDAe966FEAA0E30C82c5592632ce30333926001600160a01b031691908b908d613c12613028565b6040516001600160e01b031960e089901b1681526001600160a01b03968716600482015295909416602486015260448501929092526064840152608483015260a482015260c4016040805180830381865af4158015613c75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c999190615597565b94509250505b5093509350935093565b60606000613cc76005546001600160801b0363010000009091041690565b90508015613cdf57613cda816001613243565b613d2a565b613ce76135fe565b516001600160401b03811115613cff57613cff61482e565b604051908082528060200260200182016040528015613d28578160200160208202803683370190505b505b91505090565b8151600090815b81811015613d8257836001600160a01b0316858281518110613d5b57613d5b61526a565b60200260200101516001600160a01b031603613d7a5791506108969050565b600101613d37565b50600019949350505050565b6000613de3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166142db9092919063ffffffff16565b805190915015611da05780806020019051810190613e0191906154fb565b611da05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611132565b6000806000613e6e84612c37565b91509150613e7d85828461381a565b5091979650505050505050565b600054610100900460ff16613eb15760405162461bcd60e51b81526004016111329061599f565b613edb817fd2de0374d4479f33e63ae5ed6ca772a10463dd883a90c612050b51fab61964006142ea565b613ee482614340565b604051631797527d60e01b81526064600482018190526001600160a01b038085166024840152831660448301527306c875daA1Dc2E27dd7381EB3b6be4F99553a60991631797527d91016117ff565b6000808351600014613a8257732af59Be93d77B391Fea20322407fE46907Bf9D0E635dcb613060646097613f656135fe565b613f6d61260d565b60968a8a6040518863ffffffff1660e01b8152600401613f939796959493929190615b32565b6040805180830381865af4158015613faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd39190615597565b909590945092505050565b60008115613fec5781610896565b620186a092915050565b606061400061263d565b1561402a576040805160028082526060820183529091602083019080368337019050509050614284565b60015460048054604051630dc528a760e01b81526001600160a01b0390931691830191909152600160c81b8104600290810b6024840152600160e01b8204900b6044830152600160a81b900460ff16151560648201526000908190734B890495ae196454A8058aA4768bd5f3EE089bEE90630dc528a7906084016040805180830381865af41580156140c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e49190615597565b6003546004549294509092506001600160a01b03908116917306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe3991631c2040d5918b918b91869116614129888a614fb8565b61413b8a670de0b6b3a76400006154c2565b61414591906154d9565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452918416604484015290921660648201526084810191909152609660a482015260c401600060405180830381865af41580156141b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141d891908101906151db565b9350806001600160a01b0316866000815181106141f7576141f761526a565b60200260200101516001600160a01b03161461428057836001815181106142205761422061526a565b60200260200101518460008151811061423b5761423b61526a565b6020026020010151856000815181106142565761425661526a565b60200260200101866001815181106142705761427061526a565b6020908102919091010191909152525b5050505b949350505050565b8051600090815b818110156142ce578381815181106142ad576142ad61526a565b60200260200101516000036142c6575060019392505050565b600101614293565b5060009392505050565b50565b60606142848484600085614565565b6142f48282614635565b6110dc5760405162461bcd60e51b815260206004820152601a60248201527f496e74657266616365206973206e6f7420737570706f727465640000000000006044820152606401611132565b600054610100900460ff166143675760405162461bcd60e51b81526004016111329061599f565b6001600160a01b0381166143af5760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b6044820152606401611132565b6143d9817f4c2403fdcb3cff9b705d96bf0705858e3390412670a62c8bcba611ca7e20ab866142ea565b60006001600160a01b0316816001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015614422573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061444691906155bb565b6001600160a01b03160361448e5760405162461bcd60e51b815260206004820152600f60248201526e5a65726f20676f7665726e616e636560881b6044820152606401611132565b6144bd8161120960017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c361861520f565b6144ec4261120960017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b61520f565b61451b4361120960017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f161520f565b604080516001600160a01b0383168152426020820152438183015290517f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe2367134269181900360600190a150565b6060824710156145c65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611132565b600080866001600160a01b031685876040516145e29190615b9b565b60006040518083038185875af1925050503d806000811461461f576040519150601f19603f3d011682016040523d82523d6000602084013e614624565b606091505b5091509150612fad87838387614709565b60006001600160a01b03831661467c5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606401611132565b823b6000819003614691576000915050610896565b6040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa9250505080156146fb575060408051601f3d908101601f191682019092526146f8918101906154fb565b60015b156142ce5791506108969050565b60608315614778578251600003614771576001600160a01b0385163b6147715760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611132565b5081614284565b614284838381511561478d5781518083602001fd5b8060405162461bcd60e51b81526004016111329190614ba0565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b60006020828403121561480157600080fd5b81356001600160e01b03198116811461356c57600080fd5b6001600160a01b03811681146142d857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561486c5761486c61482e565b604052919050565b60006001600160401b0382111561488d5761488d61482e565b50601f01601f191660200190565b600082601f8301126148ac57600080fd5b81356148bf6148ba82614874565b614844565b8181528460208386010111156148d457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561490a57600080fd5b863561491581614819565b9550602087013561492581614819565b94506040870135935060608701356001600160401b038082111561494857600080fd5b6149548a838b0161489b565b9450608089013591508082111561496a57600080fd5b5061497789828a0161489b565b92505060a087013590509295509295509295565b6000806040838503121561499e57600080fd5b82356149a981614819565b946020939093013593505050565b80151581146142d857600080fd5b6000602082840312156149d757600080fd5b813561356c816149b7565b6000602082840312156149f457600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060208284031215614a2157600080fd5b813561356c81614819565b600081518084526020808501945080840160005b83811015614a5c57815187529582019590820190600101614a40565b509495945050505050565b60208152600061356c6020830184614a2c565b600081518084526020808501945080840160005b83811015614a5c578151151587529582019590820190600101614a8e565b6080808252855190820181905260009060209060a0840190828901845b82811015614aee5781516001600160a01b031684529284019290840190600101614ac9565b5050508381038285015286518082528783019183019060005b81811015614b2657835160020b83529284019291840191600101614b07565b50508481036040860152614b3a8188614a2c565b925050508281036060840152612fad8185614a7a565b60005b83811015614b6b578181015183820152602001614b53565b50506000910152565b60008151808452614b8c816020860160208601614b50565b601f01601f19169290920160200192915050565b60208152600061356c6020830184614b74565b60008083601f840112614bc557600080fd5b5081356001600160401b03811115614bdc57600080fd5b602083019150836020828501011115613a8257600080fd5b60008060208385031215614c0757600080fd5b82356001600160401b03811115614c1d57600080fd5b61294385828601614bb3565b600080600060608486031215614c3e57600080fd5b833592506020840135614c5081614819565b929592945050506040919091013590565b60006001600160401b03821115614c7a57614c7a61482e565b5060051b60200190565b600082601f830112614c9557600080fd5b81356020614ca56148ba83614c61565b82815260059290921b84018101918181019086841115614cc457600080fd5b8286015b84811015614cdf5780358352918301918301614cc8565b509695505050505050565b60008060408385031215614cfd57600080fd5b82356001600160401b0380821115614d1457600080fd5b818501915085601f830112614d2857600080fd5b81356020614d386148ba83614c61565b82815260059290921b84018101918181019089841115614d5757600080fd5b948201945b83861015614d7e578535614d6f81614819565b82529482019490820190614d5c565b96505086013592505080821115614d9457600080fd5b50614da185828601614c84565b9150509250929050565b60008060408385031215614dbe57600080fd5b823591506020830135614dd0816149b7565b809150509250929050565b600060208284031215614ded57600080fd5b81356001600160401b03811115614e0357600080fd5b611f258482850161489b565b60008060008060608587031215614e2557600080fd5b843593506020850135925060408501356001600160401b03811115614e4957600080fd5b614e5587828801614bb3565b95989497509550505050565b600060808284031215614e7357600080fd5b82601f830112614e8257600080fd5b604051608081018181106001600160401b0382111715614ea457614ea461482e565b604052806080840185811115614eb957600080fd5b845b81811015614ed3578035835260209283019201614ebb565b509195945050505050565b8060020b81146142d857600080fd5b600080600080600080600061014080898b031215614f0a57600080fd5b8835614f1581614819565b97506020890135614f2581614819565b96506040890135614f3581614819565b95506060890135614f4581614819565b94506080890135614f5581614ede565b935060a0890135614f6581614ede565b92508881018a1015614f7657600080fd5b5060c08801905092959891949750929550565b600060208284031215614f9b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561089657610896614fa2565b8060005b600481101561174f578151845260209384019390910190600101614fcf565b60006101c089835260208084018a60005b60058110156150255781516001600160a01b031683529183019190830190600101614fff565b5050505061503660c0840189614fcb565b8061014084015261504981840188614b74565b905082810361016084015261505e8187614b74565b61018084019590955250506101a0015295945050505050565b600082601f83011261508857600080fd5b815160206150986148ba83614c61565b82815260059290921b840181019181810190868411156150b757600080fd5b8286015b84811015614cdf57805183529183019183016150bb565b600080604083850312156150e557600080fd5b82516150f0816149b7565b60208401519092506001600160401b0381111561510c57600080fd5b614da185828601615077565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b8881526020808201899052610120820190604083018960005b60028110156151a15781516001600160a01b03168352918301919083019060010161517b565b50505050608082019690965260a08101949094526001600160a01b039290921660c0840152151560e0830152610100909101529392505050565b6000602082840312156151ed57600080fd5b81516001600160401b0381111561520357600080fd5b611f2584828501615077565b8181038181111561089657610896614fa2565b634e487b7160e01b600052602160045260246000fd5b828152604081016004831061525d57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b634e487b7160e01b600052603260045260246000fd5b600082601f83011261529157600080fd5b815160206152a16148ba83614c61565b82815260059290921b840181019181810190868411156152c057600080fd5b8286015b84811015614cdf5780516152d781614819565b83529183019183016152c4565b600082601f8301126152f557600080fd5b815160206153056148ba83614c61565b82815260059290921b8401810191818101908684111561532457600080fd5b8286015b84811015614cdf57805161533b816149b7565b8352918301918301615328565b6000806000806080858703121561535e57600080fd5b84516001600160401b038082111561537557600080fd5b61538188838901615280565b955060209150818701518181111561539857600080fd5b8701601f810189136153a957600080fd5b80516153b76148ba82614c61565b81815260059190911b8201840190848101908b8311156153d657600080fd5b928501925b828410156153fd5783516153ee81614ede565b825292850192908501906153db565b60408b015190985094505050508082111561541757600080fd5b61542388838901615077565b9350606087015191508082111561543957600080fd5b50615446878288016152e4565b91505092959194509250565b600181811c9082168061546657607f821691505b60208210810361548657634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761089657610896614fa2565b6000826154f657634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561550d57600080fd5b815161356c816149b7565b86815260c06020820152600061553160c0830188614b74565b82810360408401526155438188614a2c565b6001600160a01b0396871660608501529490951660808301525060a00152949350505050565b6000806040838503121561557c57600080fd5b825161558781614819565b6020939093015192949293505050565b600080604083850312156155aa57600080fd5b505080516020909101519092909150565b6000602082840312156155cd57600080fd5b815161356c81614819565b82815260a0810161356c6020830184614fcb565b8781526001600160a01b0387811660208301528681166040830152600286810b606084015285900b60808084019190915290841660a08301526101408201908360c084013798975050505050505050565b60006020828403121561564f57600080fd5b81516001600160401b0381111561566557600080fd5b8201601f8101841361567657600080fd5b80516156846148ba82614874565b81815285602083850101111561569957600080fd5b6156aa826020830160208601614b50565b95945050505050565b8281526040602082015260006142846040830184614b74565b600081518084526020808501945080840160005b83811015614a5c5781516001600160a01b0316875295820195908201906001016156e0565b60a08152600061571860a08301886156cc565b828103602084015261572a8188614a2c565b604084019690965250506001600160a01b03929092166060830152151560809091015292915050565b60008060006060848603121561576857600080fd5b8351925060208401516001600160401b038082111561578657600080fd5b61579287838801615077565b935060408601519150808211156157a857600080fd5b506157b586828701615077565b9150509250925092565b6001600160a01b038616815260a0602082018190526000906157e3908301876156cc565b82810360408401526157f581876156cc565b905082810360608401526158098186614a2c565b9050828103608084015261581d8185614a2c565b98975050505050505050565b6000806040838503121561583c57600080fd5b82516001600160401b038082111561585357600080fd5b61585f86838701615280565b9350602085015191508082111561587557600080fd5b50614da185828601615077565b85815284602082015260a0604082015260006158a160a0830186614a2c565b82810360608401526158b381866156cc565b9150508260808301529695505050505050565b87815260e0602082015260006158df60e08301896156cc565b604083018890526001600160a01b038716606084015282810360808401526159078187614a2c565b60a0840195909552505060c0015295945050505050565b8281526040602082015260006142846040830184614a2c565b60c08152600061594a60c08301896156cc565b6020830197909752506001600160a01b039485166040820152929093166060830152608082015260a00152919050565b60408152600061598d6040830185614a2c565b82810360208401526156aa8185614a2c565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60018060a01b03871681528560020b60208201528460020b604082015260c060608201526000615a1d60c0830186614a2c565b6001600160801b039490941660808301525090151560a090910152949350505050565b600080600060608486031215615a5557600080fd5b83516001600160401b03811115615a6b57600080fd5b615a7786828701615077565b9350506020840151915060408401516001600160801b0381168114615a9b57600080fd5b809150509250925092565b600080600060608486031215615abb57600080fd5b83516001600160401b0380821115615ad257600080fd5b615ade87838801615280565b9450602086015191508082111561578657600080fd5b6001600160a01b03858116825284166020820152608060408201819052600090615b20908301856156cc565b8281036060840152612fad8185614a2c565b87815286602082015260e060408201526000615b5160e08301886156cc565b6001600160a01b03871660608401526080830186905282810360a0840152615b7981866156cc565b905082810360c0840152615b8d8185614a2c565b9a9950505050505050505050565b60008251615bad818460208701614b50565b919091019291505056fea264697066735822122011df50cbf6e5dda7d4ddf275008de27810c4c75f970b454eaa98012537320e9864736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106103645760003560e01c806371ee0175116101c9578063b429afeb116100ff578063d3487997116100ad578063dfeb10321161007c578063dfeb103214610795578063e50df07d146107a8578063f77c4791146107bb578063ffb86c6a146107c357600080fd5b8063d348799714610754578063db8d55f114610767578063de3d047c1461076f578063dee1f0e41461078257600080fd5b8063b429afeb146106b9578063b77c975b146106cc578063bd38837b146106fe578063cd4c81561461070f578063ce2f184214610720578063ceee861d14610728578063d295ea701461074c57600080fd5b806387c7f770116101775780639d0bcca0116101465780639d0bcca01461065a578063a3f4df7e14610662578063ab9e3eee1461069e578063b2457556146106a657600080fd5b806387c7f77014610610578063936725ec1461058257806396b7b14e14610623578063996a6c9c1461063657600080fd5b806371ee01751461057a57806373a50ef51461058257806378327438146105a65780637cc96380146105c65780637eba7ba6146105ce5780637efc77fa146105e0578063877887821461060857600080fd5b80634ba31b011161029e578063546799631161024c57806363e277341161021b57806363e277341461052e5780636b5fba5a146105415780636ffb4c8e146105545780637063a2371461056757600080fd5b806354679963146104e35780635641ec03146104f85780635cfc1a51146105005780636207a0cf1461050a57600080fd5b80634ba31b01146104635780634e71d92d1461046b5780634fa5d854146104735780634fac6ccd1461049057806351e03fbe146104a357806352bbbb74146104b65780635412335d146104cb57600080fd5b8063261efa12116103165780633cd8045e116102e55780633cd8045e1461042f57806342fdb471146104405780634593144c146104535780634ad0b6841461045b57600080fd5b8063261efa12146103fd578063325a19f11461040557806333c5b58e1461040d57806338d52e0f1461041557600080fd5b806301e1d1141461036957806301ffc9a714610384578063066a6fc3146103a75780630acd12c7146103ba5780630e30428d146103c25780631d2dca9e146103d75780632221eb3c146103ea575b600080fd5b6103716107cb565b6040519081526020015b60405180910390f35b6103976103923660046147ef565b610856565b604051901515815260200161037b565b6103976103b53660046148f1565b61089c565b610371610a7b565b6103d56103d036600461498b565b610b9d565b005b6103d56103e53660046149c5565b610c41565b6103d56103f83660046149e2565b610daa565b606854610371565b610371610e20565b610371610e50565b6064546001600160a01b03165b60405161037b91906149fb565b6065546001600160a01b0316610422565b6103d561044e3660046149e2565b610ed0565b610371610fbf565b609754610371565b610371610fef565b6103d5611066565b61047b6110e0565b6040805192835260208301919091520161037b565b6103d561049e366004614a0f565b61114e565b6103716104b13660046149e2565b611280565b6104be611448565b60405161037b9190614a67565b6104d3611598565b60405161037b9493929190614aac565b6104eb611627565b60405161037b9190614ba0565b6103d56116bc565b600160ff1b610371565b6104eb60405180604001604052806005815260200164332e312e3760d81b81525081565b6103d561053c366004614bf4565b611755565b6103d561054f366004614a0f565b611833565b6103d56105623660046149e2565b6118c4565b6103d5610575366004614c29565b61194c565b609954610371565b6104eb60405180604001604052806005815260200164332e302e3160d81b81525081565b6103716105b4366004614a0f565b60966020526000908152604090205481565b6103716119ea565b6103716105dc3660046149e2565b5490565b6104eb60405180604001604052806009815260200168556e6973776170563360b81b81525081565b606754610371565b61037161061e36600461498b565b611a1a565b6103d5610631366004614cea565b611d00565b6104eb604051806040016040528060058152602001640c4b8c0b8d60da1b81525081565b610422611da5565b6104eb6040518060400160405280601c81526020017f556e6973776170563320436f6e7665727465722053747261746567790000000081525081565b610397611dd5565b6103716106b4366004614dab565b611e80565b6103976106c7366004614a0f565b611f2f565b6106df6106da366004614ddb565b611f54565b604080516001600160a01b03909316835260208301919091520161037b565b6098546001600160a01b0316610422565b6066546001600160a01b0316610422565b609a54610371565b6104eb60405180604001604052806005815260200164199718971b60d91b81525081565b606954610371565b6103d5610762366004614e0f565b612046565b61047b612137565b6103d561077d3660046149e2565b6121af565b610397610790366004614a0f565b61220c565b6103d56107a3366004614e61565b612291565b6103d56107b6366004614eed565b612339565b61042261260d565b61039761263d565b60006107d660975490565b6064546040516370a0823160e01b81526001600160a01b03909116906370a08231906108069030906004016149fb565b602060405180830381865afa158015610823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108479190614f89565b6108519190614fb8565b905090565b60006001600160e01b03198216631e94dddf60e01b148061088757506001600160e01b0319821663f73147b360e01b145b8061089657506108968261268b565b92915050565b60008060006108a96126b0565b91509150606073__$166cd655d2cd990700b75f7db5b5f84c53$__63911ec05360976040518060a001604052808e6001600160a01b03166001600160a01b031681526020018d6001600160a01b03166001600160a01b0316815260200161090e61260d565b6001600160a01b039081168252609854811660208084019190915260655490911660409283015281516080810183528e8152908101899052808201889052606081018b905290516001600160e01b031960e086901b16815261097f939291908d908d90600190609690600401614fee565b600060405180830381865af415801561099c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c491908101906150d2565b90945090506109d281612702565b60006010558380156109e757506109e7612731565b156109f2576001600f555b606480546040516368f9467b60e01b81526001600160a01b039091166004820152602481018490526097604482015273__$8f1afe7577f9ab973017c74eca19b86f3c$__916368f9467b910160006040518083038186803b158015610a5657600080fd5b505af4158015610a6a573d6000803e3d6000fd5b505050505050509695505050505050565b606554606454604051633e53813360e11b81526000926001600160a01b03908116921690839073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90637ca7026690610acd9086908690600401615118565b602060405180830381865af4158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190614f89565b90506000806000610b1d612743565b92509250925073__$7dde4232fad0cb3c495beb9e735b7d0c63$__639ad00ec2868686868b6040518663ffffffff1660e01b8152600401610b62959493929190615132565b60006040518083038186803b158015610b7a57600080fd5b505af4158015610b8e573d6000803e3d6000fd5b50929998505050505050505050565b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63142395ef610bbf61260d565b6040516001600160e01b031960e084901b1681526001600160a01b03918216600482015290851660248201526044810184905260640160006040518083038186803b158015610c0d57600080fd5b505af4158015610c21573d6000803e3d6000fd5b5050506001600160a01b0390921660009081526096602052604090205550565b6000610c4b61260d565b60405163124fdbb760e21b815290915073__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063493f6edc90610c859084906004016149fb565b60006040518083038186803b158015610c9d57600080fd5b505af4158015610cb1573d6000803e3d6000fd5b50505050600080610cc06126b0565b604080518082019091526098546001600160a01b03168152919350915060009073__$166cd655d2cd990700b75f7db5b5f84c53$__9063b6fda8139060979060019060208101610d0f8a61275e565b6001600160a01b039081169091526065546040516001600160e01b031960e088901b168152610d4f959493928a928c929116908e90609690600401615162565b600060405180830381865af4158015610d6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d9491908101906151db565b9050610d9f81612702565b505042601055505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610dcc61260d565b6040518263ffffffff1660e01b8152600401610de891906149fb565b60006040518083038186803b158015610e0057600080fd5b505af4158015610e14573d6000803e3d6000fd5b505050600f9190915550565b60006108516105dc60017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b61520f565b600073__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610e7461260d565b6040518263ffffffff1660e01b8152600401610e9091906149fb565b60006040518083038186803b158015610ea857600080fd5b505af4158015610ebc573d6000803e3d6000fd5b50505050610ec86127c2565b509092915050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc610ef261260d565b6040518263ffffffff1660e01b8152600401610f0e91906149fb565b60006040518083038186803b158015610f2657600080fd5b505af4158015610f3a573d6000803e3d6000fd5b5073__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250636bffb346915060069050836003811115610f6f57610f6f615222565b6040518363ffffffff1660e01b8152600401610f8c929190615238565b60006040518083038186803b158015610fa457600080fd5b505af4158015610fb8573d6000803e3d6000fd5b5050505050565b60006108516105dc60017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f161520f565b604051630a3c2bb160e21b81526001600482015260009073__$166cd655d2cd990700b75f7db5b5f84c53$__906328f0aec490602401602060405180830381865af4158015611042573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108519190614f89565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63d19cc38a61108861260d565b6040518263ffffffff1660e01b81526004016110a491906149fb565b60006040518083038186803b1580156110bc57600080fd5b505af41580156110d0573d6000803e3d6000fd5b505050506110dc612893565b5050565b60655460408051808201909152600a81526914d08e8811195b9a595960b21b60208201526000918291906001600160a01b0316331461113b5760405162461bcd60e51b81526004016111329190614ba0565b60405180910390fd5b50611146600161294f565b915091509091565b33301461119d5760405162461bcd60e51b815260206004820152601b60248201527f496e637265617365207265766973696f6e20666f7262696464656e00000000006044820152606401611132565b60006111cd6105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b6111d8906001614fb8565b905061120c8161120960017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b55565b61123b8261120960017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e461520f565b604080518281526001600160a01b03841660208201527ff27e2ef832a4eb8ed8ec553b875eecd44764cda95b1c24170e281539e0a869c8910160405180910390a15050565b606554606454604051633e53813360e11b81526000926001600160a01b03908116921690839073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90637ca70266906112d29086908690600401615118565b602060405180830381865af41580156112ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113139190614f89565b9050808511156113bf5760008061133261132d848961520f565b612b41565b604051631594b05b60e01b8152909850919350915073__$7dde4232fad0cb3c495beb9e735b7d0c63$__90631594b05b906113799087908790879087908c90600401615132565b602060405180830381865af4158015611396573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ba9190614f89565b925050505b6040516333bbb20360e11b815260048101869052602481018290526001600160a01b0380841660448301528416606482015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9063677764069060840160006040518083038186803b15801561142857600080fd5b505af415801561143c573d6000803e3d6000fd5b50505050505050919050565b600280546040805183815260608082018352936001600160a01b0390931692909160208301908036833750506003546040516370a0823160e01b81529294506001600160a01b0316916370a0823191506114a69084906004016149fb565b602060405180830381865afa1580156114c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e79190614f89565b826000815181106114fa576114fa61526a565b6020908102919091010152600480546040516370a0823160e01b81526001600160a01b03909116916370a0823191611534918591016149fb565b602060405180830381865afa158015611551573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614f89565b826001815181106115885761158861526a565b6020026020010181815250505090565b604051636e81b62960e01b81526001600482015260609081908190819073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__90636e81b62990602401600060405180830381865af41580156115f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526116199190810190615348565b935093509350935090919293565b60606064600601805461163990615452565b80601f016020809104026020016040519081016040528092919081815260200182805461166590615452565b80156116b25780601f10611687576101008083540402835291602001916116b2565b820191906000526020600020905b81548152906001019060200180831161169557829003601f168201915b5050505050905090565b6116c4612b72565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63bd0206826116e661260d565b6064805460655460405160e086901b6001600160e01b03191681526001600160a01b03948516600482015291841660248301529290921660448301520160006040518083038186803b15801561173b57600080fd5b505af415801561174f573d6000803e3d6000fd5b50505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc61177761260d565b6040518263ffffffff1660e01b815260040161179391906149fb565b60006040518083038186803b1580156117ab57600080fd5b505af41580156117bf573d6000803e3d6000fd5b5050604051637fc1c15b60e01b815273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9250637fc1c15b91506117ff906064908690869060040161548c565b60006040518083038186803b15801561181757600080fd5b505af415801561182b573d6000803e3d6000fd5b505050505050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc61185561260d565b6040518263ffffffff1660e01b815260040161187191906149fb565b60006040518083038186803b15801561188957600080fd5b505af415801561189d573d6000803e3d6000fd5b5050600280546001600160a01b0319166001600160a01b0394909416939093179092555050565b73__$8f1afe7577f9ab973017c74eca19b86f3c$__63d2c3cf256118e661260d565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024810184905260440160006040518083038186803b15801561192c57600080fd5b505af4158015611940573d6000803e3d6000fd5b50505060999190915550565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63ed6b63c1606485858561197361260d565b6040516001600160e01b031960e088901b168152600481019590955260248501939093526001600160a01b039182166044850152606484015216608482015260a40160006040518083038186803b1580156119cd57600080fd5b505af41580156119e1573d6000803e3d6000fd5b50505050505050565b60006108516105dc60017f22573091f17911fb166032a3d9e0554aa73d31b7b7ddea4a4dd2995650af84bd61520f565b6000611a246147a7565b611a3084826000612bbd565b805160408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611a7c5760405162461bcd60e51b81526004016111329190614ba0565b5060408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015283611ac25760405162461bcd60e51b81526004016111329190614ba0565b5060001981606001511415604051806040016040528060118152602001701514cb4c4d081ddc9bdb99c8185cdcd95d607a1b81525090611b155760405162461bcd60e51b81526004016111329190614ba0565b50600080611b236001612c37565b608085015160405163513cfdb360e11b81526001600160a01b038a16600482015260248101919091526044810183905260648181018390526084820152919350915073__$8f1afe7577f9ab973017c74eca19b86f3c$__9063a279fb669060a401602060405180830381865af4158015611ba1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc59190614f89565b60808401526000620186a0611bdc6103e882614fb8565b611be690886154c2565b611bf091906154d9565b905080846080015110611c1c578351611c14906001600160a01b0389169088612d01565b859450611ced565b82600003611c5757611c336103e8620186a0614fb8565b620186a08560800151611c4691906154c2565b611c5091906154d9565b9450611ced565b6000620186a0611c6a6103e860026154c2565b611c7790620186a0614fb8565b611c8190896154c2565b611c8b91906154d9565b9050611ca6856080015182611ca0919061520f565b86612d53565b506000611cb289612fb8565b9050828111611ce657611cca6103e8620186a0614fb8565b611cd7620186a0836154c2565b611ce191906154d9565b611ce8565b875b965050505b611cf5613028565b505050505092915050565b60985460408051808201909152600a81526914d08e8811195b9a595960b21b6020820152906001600160a01b03163314611d4d5760405162461bcd60e51b81526004016111329190614ba0565b5080518251146040518060400160405280600d81526020016c54532d3139206c656e6774687360981b81525090611d975760405162461bcd60e51b81526004016111329190614ba0565b50611da0613028565b505050565b60006108516105dc60017fbfaaa2fb63266ff27c2da975f5894955056f50419af651a81f6c5060581857e461520f565b6000611ddf61263d565b158015611df15750611def612731565b155b8015610851575060985460405163119aa29360e11b8152600160048201526001600160a01b03909116602482015273__$166cd655d2cd990700b75f7db5b5f84c53$__906323354526906044015b602060405180830381865af4158015611e5c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085191906154fb565b6065546064546040516001625acc3160e01b03198152600092839273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9263ffa533cf92611ed2926001600160a01b0391821692911690600401615118565b602060405180830381865af4158015611eef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f139190614f89565b90508015611f2857611f25818461303e565b91505b5092915050565b6000611f3961260d565b6001600160a01b0316826001600160a01b0316149050919050565b6005546000908190630100000090046001600160801b0316818115611f8157611f7c826130e2565b611f9f565b60408051600280825260608201835290916020830190803683375050505b905073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__6350d2e0ba60018784611fc761260d565b6098546040516001600160e01b031960e088901b168152611ffb95949392916001600160a01b031690609690600401615518565b6040805180830381865af4158015612017573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203b9190615569565b935093505050915091565b60015460408051808201909152601a81527f5533532d3131204e6f742063616c6c6261636b2063616c6c65720000000000006020820152906001600160a01b031633146120a65760405162461bcd60e51b81526004016111329190614ba0565b5083156120f4576004546120f49033908690600160a81b900460ff166120d7576003546001600160a01b03166120e4565b6004546001600160a01b03165b6001600160a01b03169190612d01565b821561174f5760045461174f9033908590600160a81b900460ff16612124576004546001600160a01b03166120e4565b6003546001600160a01b03169190612d01565b604051630ba4ccab60e11b815260016004820152600090819073__$166cd655d2cd990700b75f7db5b5f84c53$__906317499956906024016040805180830381865af415801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111469190615597565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__636d51f04360646121d361260d565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260448101849052606401610f8c565b6000816001600160a01b031661222061260d565b6001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa15801561225d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228191906155bb565b6001600160a01b03161492915050565b73__$7dde4232fad0cb3c495beb9e735b7d0c63$__63493f6edc6122b361260d565b6040518263ffffffff1660e01b81526004016122cf91906149fb565b60006040518083038186803b1580156122e757600080fd5b505af41580156122fb573d6000803e3d6000fd5b5050604051630593c4c960e01b815273__$79fe6ec7a3db45dafbed12dca1c6dad764$__9250630593c4c99150610f8c9060069085906004016155d8565b600054610100900460ff16158080156123595750600054600160ff909116105b806123735750303b158015612373575060005460ff166001145b6123d65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401611132565b6000805460ff1916600117905580156123f9576000805461ff0019166101001790555b61240488888861316c565b73__$166cd655d2cd990700b75f7db5b5f84c53$__63adc4343460018a8888888d6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612462573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248691906155bb565b896040518863ffffffff1660e01b81526004016124a997969594939291906155ec565b60006040518083038186803b1580156124c157600080fd5b505af41580156124d5573d6000803e3d6000fd5b505060405163bd85be2960e01b81526001600482015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__9250637fc1c15b915060649073__$166cd655d2cd990700b75f7db5b5f84c53$__9063bd85be2990602401600060405180830381865af4158015612548573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612570919081019061563d565b6040518363ffffffff1660e01b815260040161258d9291906156b3565b60006040518083038186803b1580156125a557600080fd5b505af41580156125b9573d6000803e3d6000fd5b505050508015612603576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60006108516105dc60017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c361861520f565b609854604051633934e59d60e11b8152600160048201526001600160a01b03909116602482015260009073__$166cd655d2cd990700b75f7db5b5f84c53$__90637269cb3a90604401611e3f565b60006001600160e01b0319821663c19fa56160e01b148061089657506108968261320e565b6000806126bd6001612c37565b92508290506126ca6107cb565b6126d4919061520f565b600554909150630100000090046001600160801b031680156126fd576126fb816000613243565b505b509091565b805160021480156127185750612716612731565b155b156127295761272681613363565b50505b6110dc613028565b6006546000906108519060ff1661346b565b6000806000612753600019612b41565b925092509250909192565b6000816001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561279e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089691906155bb565b6064546000906060908190839081906127e3906001600160a01b0316613488565b9150915073__$8f1afe7577f9ab973017c74eca19b86f3c$__637325f33f8361280b856134f4565b6098546040516001600160e01b031960e086901b16815261284193929187916001600160a01b0390911690600190600401615705565b600060405180830381865af415801561285e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128869190810190615753565b9450945094505050909192565b60608060008060006128a3613573565b609854929550909350915073__$8f1afe7577f9ab973017c74eca19b86f3c$__9063e99de4da906001600160a01b03166128db6135fe565b8686866040518663ffffffff1660e01b81526004016128fe9594939291906157bf565b600060405180830381865af415801561291b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129439190810190615829565b90969095509350505050565b60008060008061295f6001612c37565b9150915061296c85613692565b612abf576000806000806000612980613747565b9450945094509450945060006129946127c2565b5050905060008060006129e78e80156129ac57508415155b80156129d35750609954620186a0906129c69087906154c2565b6129d091906154d9565b88115b6129de5760006129e0565b875b8b8661381a565b93509350935050612a1787856129fd9190614fb8565b84612a088486614fb8565b612a129190614fb8565b613a59565b909d509b50612a299250613a89915050565b604080518981526020810189905290810187905260608101869052608081018b905260a081018a905260c0810184905260e081018390527ff87a9dead982c86370b885093f79ded2c9a614d95d83c0c20f68e13e3b9b7d3f906101000160405180910390a1612aaa612a9b878c614fb8565b612aa58486614fb8565b613a8b565b9950612ab6858a614fb8565b98505050505050505b6098546064546040516323c1ae5960e11b815273__$8f1afe7577f9ab973017c74eca19b86f3c$__926347835cb292612b0a926001600160a01b039283169290911690600401615118565b60006040518083038186803b158015612b2257600080fd5b505af4158015612b36573d6000803e3d6000fd5b505050505050915091565b6000806000806000612b536001612c37565b91509150612b62868284613aa5565b5091989097509095509350505050565b6000612b7c613ca9565b90507f768a28cb3459382a3d2173feb2dad0235f8de680b109872da581a3aa269fe5f481604051612bad9190614a67565b60405180910390a16110dc613028565b612bc56135fe565b604083018190526001600160a01b038085166020850152609854168352612bec9084613d30565b6060830152612bfa83612fb8565b608083015280612c24576040820151606454612c1f91906001600160a01b0316613d30565b612c2a565b81606001515b60a0909201919091525050565b6000808215612cf4576064546000908190612c5a906001600160a01b0316613488565b9150915073__$8f1afe7577f9ab973017c74eca19b86f3c$__633643611860976064612c85866134f4565b86866040518663ffffffff1660e01b8152600401612ca7959493929190615882565b6040805180830381865af4158015612cc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce79190615597565b9094509250612cfc915050565b505060975460005b915091565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611da0908490613d8e565b600080612d706005546001600160801b0363010000009091041690565b90506000612d7d826130e2565b9050600073__$8f1afe7577f9ab973017c74eca19b86f3c$__630252e2c78787604001518860600151896000015187898c60a001516040518863ffffffff1660e01b8152600401612dd497969594939291906158c6565b602060405180830381865af4158015612df1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e159190614f89565b90508015612e87576000612e2a826000613243565b600554909150630100000090046001600160801b0316612e4a908561520f565b91507faebc771af58936b05e89b0be7d3f9761480181abcd4a649fbdd01753fda169708282604051612e7d92919061591e565b60405180910390a1505b600073__$e930d50fb5f4f1298547dbcb2bb0591990$__63c432aee1876040015188606001518960000151612ec2612ebd61260d565b61275e565b6000198d14612ee0578c8c60800151612edb9190614fb8565b612ee2565b8c5b60966040518763ffffffff1660e01b8152600401612f0596959493929190615937565b602060405180830381865af4158015612f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f469190614f89565b905085608001518110156040518060400160405280601681526020017554532d32302062616c616e636520646563726561736560501b81525090612f9d5760405162461bcd60e51b81526004016111329190614ba0565b506080860151612fad908261520f565b979650505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190612fe79030906004016149fb565b602060405180830381865afa158015613004573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190614f89565b60006130326127c2565b50506097819055919050565b6000613048612731565b156130d15760408051600280825260608201835260009260208301908036833701905050905083816000815181106130825761308261526a565b6020026020010181815250507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d0581826040516130bf92919061597a565b60405180910390a16000915050610896565b6130db8383613e60565b9050610896565b60405163a7aced0960e01b8152600160048201526001600160801b038216602482015260609073__$166cd655d2cd990700b75f7db5b5f84c53$__9063a7aced0990604401600060405180830381865af4158015613144573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261089691908101906151db565b600054610100900460ff166131935760405162461bcd60e51b81526004016111329061599f565b61319d8383613e8a565b609880546001600160a01b0319166001600160a01b0383161790556131c66064620186a06154d9565b6099557fe4166dfcf23bbd3e3f764a99dc8fa740554c03c82d6019b81cf265f396f6f2fe6131f86064620186a06154d9565b60405190815260200160405180910390a1505050565b60006001600160e01b0319821663b7b79fa960e01b148061089657506301ffc9a760e01b6001600160e01b0319831614610896565b60606000808361325b57613255612137565b90925090505b604051633ae60bcb60e01b8152600160048201526001600160801b038616602482015273__$166cd655d2cd990700b75f7db5b5f84c53$__90633ae60bcb90604401600060405180830381865af41580156132ba573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526132e291908101906151db565b92508361335b57604051632b25a6cf60e01b815260016004820152602481018390526044810182905273__$166cd655d2cd990700b75f7db5b5f84c53$__90632b25a6cf9060640160006040518083038186803b15801561334257600080fd5b505af4158015613356573d6000803e3d6000fd5b505050505b505092915050565b60015460048054600554604051638008936760e01b815260609460009473__$166cd655d2cd990700b75f7db5b5f84c53$__946380089367946133e9946001600160a01b0390941693600160c81b8304600290810b94600160e01b850490910b938c93630100000090046001600160801b031692600160a81b90910460ff1691016159ea565b600060405180830381865af4158015613406573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261342e9190810190615a40565b600580546001600160801b0390921663010000000272ffffffffffffffffffffffffffffffff000000199092169190911790559094909350915050565b6000600182600381111561348157613481615222565b1192915050565b606060006134946135fe565b91506134a08284613d30565b90506000198114156040518060400160405280600f81526020016e53423a2057726f6e672076616c756560881b815250906134ee5760405162461bcd60e51b81526004016111329190614ba0565b50915091565b606060006135126005546001600160801b0363010000009091041690565b9050801561352857613523816130e2565b61356c565b82516001600160401b038111156135415761354161482e565b60405190808252806020026020018201604052801561356a578160200160208202803683370190505b505b9392505050565b60405163af31673360e01b8152600160048201526060908190819073__$166cd655d2cd990700b75f7db5b5f84c53$__9063af31673390602401600060405180830381865af41580156135ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135f29190810190615aa6565b91959094509092509050565b6040805160028082526060808301845292602083019080368337505060035482519293506001600160a01b03169183915060009061363e5761363e61526a565b6001600160a01b03928316602091820292909201015260045482519116908290600190811061366f5761366f61526a565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b600061369c61263d565b15604051806040016040528060148152602001735533532d31204e65656420726562616c616e636560601b815250906136e85760405162461bcd60e51b81526004016111329190614ba0565b506136f1612731565b15604051806040016040528060158152602001745533532d313420467573652069732061637469766560581b8152509061373e5760405162461bcd60e51b81526004016111329190614ba0565b50600092915050565b600080600080600080600061375a612893565b60645491935091506001600160a01b031673__$166cd655d2cd990700b75f7db5b5f84c53$__6334d2ec3d8261378e61260d565b86866040518563ffffffff1660e01b81526004016137af9493929190615af4565b602060405180830381865af41580156137cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f09190614f89565b97506137fc8383613f33565b60009850909550935061380e81612fb8565b95505050509091929394565b6064546000908190819081906001600160a01b03168187891161383e576000613848565b613848888a61520f565b90506000620186a08860976002015461386191906154c2565b61386b91906154d9565b82119050600061387a84612fb8565b6001600160a01b03851660009081526096602052604090205490915061389f90613fde565b8a111561398e5781806138b25750898110155b1561397a5760655473__$8f1afe7577f9ab973017c74eca19b86f3c$__9063890ffb849086908d906001600160a01b03166138ed868f614fb8565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015260248101939093529216604482015260648101919091526084810184905260a4016040805180830381865af415801561394e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139729190615597565b50965061398e565b61398660008b8b613aa5565b909a50985050505b8115613a1c576000806139a086613488565b60985491935091506000906139c0906001600160a01b0316878585613ff6565b90506139cb8161428c565b613a185760006139da82613363565b5090507f59400c8c523464b521238ea8f50e923f2bc64663557e6afec92a97f7efe92d058282604051613a0e92919061597a565b60405180910390a1505b5050505b613a24613028565b9550613a2f84612fb8565b9450613a49613a3e828b614fb8565b88612a08888a614fb8565b9850505050505093509350935093565b60008083831115613a7557613a6e848461520f565b9150613a82565b613a7f838561520f565b90505b9250929050565b565b6000818311613a9b57600061356c565b61356c828461520f565b60008060008060006000198814613ae957620186a0613ac66103e882614fb8565b613ad0898b614fb8565b613ada91906154c2565b613ae491906154d9565b613aeb565b875b90508015801590613afb57508515155b15613c9f57613b086147a7565b606454613b20906001600160a01b0316826001612bbd565b80516020820151604051637a55caf360e01b815273__$8f1afe7577f9ab973017c74eca19b86f3c$__92637a55caf392613b5c92600401615118565b602060405180830381865af4158015613b79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9d9190614f89565b9450670de0b6b3a764000085613bbc613bb68585612d53565b8b613a8b565b613bc691906154c2565b613bd091906154d9565b6065546020830151608084015192985073__$8f1afe7577f9ab973017c74eca19b86f3c$__92632ce30333926001600160a01b031691908b908d613c12613028565b6040516001600160e01b031960e089901b1681526001600160a01b03968716600482015295909416602486015260448501929092526064840152608483015260a482015260c4016040805180830381865af4158015613c75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c999190615597565b94509250505b5093509350935093565b60606000613cc76005546001600160801b0363010000009091041690565b90508015613cdf57613cda816001613243565b613d2a565b613ce76135fe565b516001600160401b03811115613cff57613cff61482e565b604051908082528060200260200182016040528015613d28578160200160208202803683370190505b505b91505090565b8151600090815b81811015613d8257836001600160a01b0316858281518110613d5b57613d5b61526a565b60200260200101516001600160a01b031603613d7a5791506108969050565b600101613d37565b50600019949350505050565b6000613de3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166142db9092919063ffffffff16565b805190915015611da05780806020019051810190613e0191906154fb565b611da05760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611132565b6000806000613e6e84612c37565b91509150613e7d85828461381a565b5091979650505050505050565b600054610100900460ff16613eb15760405162461bcd60e51b81526004016111329061599f565b613edb817fd2de0374d4479f33e63ae5ed6ca772a10463dd883a90c612050b51fab61964006142ea565b613ee482614340565b604051631797527d60e01b81526064600482018190526001600160a01b0380851660248401528316604483015273__$7dde4232fad0cb3c495beb9e735b7d0c63$__91631797527d91016117ff565b6000808351600014613a825773__$e930d50fb5f4f1298547dbcb2bb0591990$__635dcb613060646097613f656135fe565b613f6d61260d565b60968a8a6040518863ffffffff1660e01b8152600401613f939796959493929190615b32565b6040805180830381865af4158015613faf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd39190615597565b909590945092505050565b60008115613fec5781610896565b620186a092915050565b606061400061263d565b1561402a576040805160028082526060820183529091602083019080368337019050509050614284565b60015460048054604051630dc528a760e01b81526001600160a01b0390931691830191909152600160c81b8104600290810b6024840152600160e01b8204900b6044830152600160a81b900460ff1615156064820152600090819073__$166cd655d2cd990700b75f7db5b5f84c53$__90630dc528a7906084016040805180830381865af41580156140c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e49190615597565b6003546004549294509092506001600160a01b039081169173__$b1ba452cecccdd06eb05ace2d0a762c7e1$__91631c2040d5918b918b91869116614129888a614fb8565b61413b8a670de0b6b3a76400006154c2565b61414591906154d9565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452918416604484015290921660648201526084810191909152609660a482015260c401600060405180830381865af41580156141b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526141d891908101906151db565b9350806001600160a01b0316866000815181106141f7576141f761526a565b60200260200101516001600160a01b03161461428057836001815181106142205761422061526a565b60200260200101518460008151811061423b5761423b61526a565b6020026020010151856000815181106142565761425661526a565b60200260200101866001815181106142705761427061526a565b6020908102919091010191909152525b5050505b949350505050565b8051600090815b818110156142ce578381815181106142ad576142ad61526a565b60200260200101516000036142c6575060019392505050565b600101614293565b5060009392505050565b50565b60606142848484600085614565565b6142f48282614635565b6110dc5760405162461bcd60e51b815260206004820152601a60248201527f496e74657266616365206973206e6f7420737570706f727465640000000000006044820152606401611132565b600054610100900460ff166143675760405162461bcd60e51b81526004016111329061599f565b6001600160a01b0381166143af5760405162461bcd60e51b815260206004820152600f60248201526e2d32b9379031b7b73a3937b63632b960891b6044820152606401611132565b6143d9817f4c2403fdcb3cff9b705d96bf0705858e3390412670a62c8bcba611ca7e20ab866142ea565b60006001600160a01b0316816001600160a01b0316635aa6e6756040518163ffffffff1660e01b8152600401602060405180830381865afa158015614422573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061444691906155bb565b6001600160a01b03160361448e5760405162461bcd60e51b815260206004820152600f60248201526e5a65726f20676f7665726e616e636560881b6044820152606401611132565b6144bd8161120960017f5165972ef41194f06c5007493031d0b927c20741adcb74403b954009fd2c361861520f565b6144ec4261120960017f6f55f470bdc9cb5f04223fd822021061668e4dccb43e8727b295106dc9769c8b61520f565b61451b4361120960017f812a673dfca07956350df10f8a654925f561d7a0da09bdbe79e653939a14d9f161520f565b604080516001600160a01b0383168152426020820152438183015290517f1a2dd071001ebf6e03174e3df5b305795a4ad5d41d8fdb9ba41dbbe2367134269181900360600190a150565b6060824710156145c65760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611132565b600080866001600160a01b031685876040516145e29190615b9b565b60006040518083038185875af1925050503d806000811461461f576040519150601f19603f3d011682016040523d82523d6000602084013e614624565b606091505b5091509150612fad87838387614709565b60006001600160a01b03831661467c5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606401611132565b823b6000819003614691576000915050610896565b6040516301ffc9a760e01b81526001600160e01b0319841660048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa9250505080156146fb575060408051601f3d908101601f191682019092526146f8918101906154fb565b60015b156142ce5791506108969050565b60608315614778578251600003614771576001600160a01b0385163b6147715760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611132565b5081614284565b614284838381511561478d5781518083602001fd5b8060405162461bcd60e51b81526004016111329190614ba0565b6040518060c0016040528060006001600160a01b0316815260200160006001600160a01b03168152602001606081526020016000815260200160008152602001600081525090565b60006020828403121561480157600080fd5b81356001600160e01b03198116811461356c57600080fd5b6001600160a01b03811681146142d857600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561486c5761486c61482e565b604052919050565b60006001600160401b0382111561488d5761488d61482e565b50601f01601f191660200190565b600082601f8301126148ac57600080fd5b81356148bf6148ba82614874565b614844565b8181528460208386010111156148d457600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561490a57600080fd5b863561491581614819565b9550602087013561492581614819565b94506040870135935060608701356001600160401b038082111561494857600080fd5b6149548a838b0161489b565b9450608089013591508082111561496a57600080fd5b5061497789828a0161489b565b92505060a087013590509295509295509295565b6000806040838503121561499e57600080fd5b82356149a981614819565b946020939093013593505050565b80151581146142d857600080fd5b6000602082840312156149d757600080fd5b813561356c816149b7565b6000602082840312156149f457600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060208284031215614a2157600080fd5b813561356c81614819565b600081518084526020808501945080840160005b83811015614a5c57815187529582019590820190600101614a40565b509495945050505050565b60208152600061356c6020830184614a2c565b600081518084526020808501945080840160005b83811015614a5c578151151587529582019590820190600101614a8e565b6080808252855190820181905260009060209060a0840190828901845b82811015614aee5781516001600160a01b031684529284019290840190600101614ac9565b5050508381038285015286518082528783019183019060005b81811015614b2657835160020b83529284019291840191600101614b07565b50508481036040860152614b3a8188614a2c565b925050508281036060840152612fad8185614a7a565b60005b83811015614b6b578181015183820152602001614b53565b50506000910152565b60008151808452614b8c816020860160208601614b50565b601f01601f19169290920160200192915050565b60208152600061356c6020830184614b74565b60008083601f840112614bc557600080fd5b5081356001600160401b03811115614bdc57600080fd5b602083019150836020828501011115613a8257600080fd5b60008060208385031215614c0757600080fd5b82356001600160401b03811115614c1d57600080fd5b61294385828601614bb3565b600080600060608486031215614c3e57600080fd5b833592506020840135614c5081614819565b929592945050506040919091013590565b60006001600160401b03821115614c7a57614c7a61482e565b5060051b60200190565b600082601f830112614c9557600080fd5b81356020614ca56148ba83614c61565b82815260059290921b84018101918181019086841115614cc457600080fd5b8286015b84811015614cdf5780358352918301918301614cc8565b509695505050505050565b60008060408385031215614cfd57600080fd5b82356001600160401b0380821115614d1457600080fd5b818501915085601f830112614d2857600080fd5b81356020614d386148ba83614c61565b82815260059290921b84018101918181019089841115614d5757600080fd5b948201945b83861015614d7e578535614d6f81614819565b82529482019490820190614d5c565b96505086013592505080821115614d9457600080fd5b50614da185828601614c84565b9150509250929050565b60008060408385031215614dbe57600080fd5b823591506020830135614dd0816149b7565b809150509250929050565b600060208284031215614ded57600080fd5b81356001600160401b03811115614e0357600080fd5b611f258482850161489b565b60008060008060608587031215614e2557600080fd5b843593506020850135925060408501356001600160401b03811115614e4957600080fd5b614e5587828801614bb3565b95989497509550505050565b600060808284031215614e7357600080fd5b82601f830112614e8257600080fd5b604051608081018181106001600160401b0382111715614ea457614ea461482e565b604052806080840185811115614eb957600080fd5b845b81811015614ed3578035835260209283019201614ebb565b509195945050505050565b8060020b81146142d857600080fd5b600080600080600080600061014080898b031215614f0a57600080fd5b8835614f1581614819565b97506020890135614f2581614819565b96506040890135614f3581614819565b95506060890135614f4581614819565b94506080890135614f5581614ede565b935060a0890135614f6581614ede565b92508881018a1015614f7657600080fd5b5060c08801905092959891949750929550565b600060208284031215614f9b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561089657610896614fa2565b8060005b600481101561174f578151845260209384019390910190600101614fcf565b60006101c089835260208084018a60005b60058110156150255781516001600160a01b031683529183019190830190600101614fff565b5050505061503660c0840189614fcb565b8061014084015261504981840188614b74565b905082810361016084015261505e8187614b74565b61018084019590955250506101a0015295945050505050565b600082601f83011261508857600080fd5b815160206150986148ba83614c61565b82815260059290921b840181019181810190868411156150b757600080fd5b8286015b84811015614cdf57805183529183019183016150bb565b600080604083850312156150e557600080fd5b82516150f0816149b7565b60208401519092506001600160401b0381111561510c57600080fd5b614da185828601615077565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039586168152602081019490945260408401929092526060830152909116608082015260a00190565b8881526020808201899052610120820190604083018960005b60028110156151a15781516001600160a01b03168352918301919083019060010161517b565b50505050608082019690965260a08101949094526001600160a01b039290921660c0840152151560e0830152610100909101529392505050565b6000602082840312156151ed57600080fd5b81516001600160401b0381111561520357600080fd5b611f2584828501615077565b8181038181111561089657610896614fa2565b634e487b7160e01b600052602160045260246000fd5b828152604081016004831061525d57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b634e487b7160e01b600052603260045260246000fd5b600082601f83011261529157600080fd5b815160206152a16148ba83614c61565b82815260059290921b840181019181810190868411156152c057600080fd5b8286015b84811015614cdf5780516152d781614819565b83529183019183016152c4565b600082601f8301126152f557600080fd5b815160206153056148ba83614c61565b82815260059290921b8401810191818101908684111561532457600080fd5b8286015b84811015614cdf57805161533b816149b7565b8352918301918301615328565b6000806000806080858703121561535e57600080fd5b84516001600160401b038082111561537557600080fd5b61538188838901615280565b955060209150818701518181111561539857600080fd5b8701601f810189136153a957600080fd5b80516153b76148ba82614c61565b81815260059190911b8201840190848101908b8311156153d657600080fd5b928501925b828410156153fd5783516153ee81614ede565b825292850192908501906153db565b60408b015190985094505050508082111561541757600080fd5b61542388838901615077565b9350606087015191508082111561543957600080fd5b50615446878288016152e4565b91505092959194509250565b600181811c9082168061546657607f821691505b60208210810361548657634e487b7160e01b600052602260045260246000fd5b50919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b808202811582820484141761089657610896614fa2565b6000826154f657634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561550d57600080fd5b815161356c816149b7565b86815260c06020820152600061553160c0830188614b74565b82810360408401526155438188614a2c565b6001600160a01b0396871660608501529490951660808301525060a00152949350505050565b6000806040838503121561557c57600080fd5b825161558781614819565b6020939093015192949293505050565b600080604083850312156155aa57600080fd5b505080516020909101519092909150565b6000602082840312156155cd57600080fd5b815161356c81614819565b82815260a0810161356c6020830184614fcb565b8781526001600160a01b0387811660208301528681166040830152600286810b606084015285900b60808084019190915290841660a08301526101408201908360c084013798975050505050505050565b60006020828403121561564f57600080fd5b81516001600160401b0381111561566557600080fd5b8201601f8101841361567657600080fd5b80516156846148ba82614874565b81815285602083850101111561569957600080fd5b6156aa826020830160208601614b50565b95945050505050565b8281526040602082015260006142846040830184614b74565b600081518084526020808501945080840160005b83811015614a5c5781516001600160a01b0316875295820195908201906001016156e0565b60a08152600061571860a08301886156cc565b828103602084015261572a8188614a2c565b604084019690965250506001600160a01b03929092166060830152151560809091015292915050565b60008060006060848603121561576857600080fd5b8351925060208401516001600160401b038082111561578657600080fd5b61579287838801615077565b935060408601519150808211156157a857600080fd5b506157b586828701615077565b9150509250925092565b6001600160a01b038616815260a0602082018190526000906157e3908301876156cc565b82810360408401526157f581876156cc565b905082810360608401526158098186614a2c565b9050828103608084015261581d8185614a2c565b98975050505050505050565b6000806040838503121561583c57600080fd5b82516001600160401b038082111561585357600080fd5b61585f86838701615280565b9350602085015191508082111561587557600080fd5b50614da185828601615077565b85815284602082015260a0604082015260006158a160a0830186614a2c565b82810360608401526158b381866156cc565b9150508260808301529695505050505050565b87815260e0602082015260006158df60e08301896156cc565b604083018890526001600160a01b038716606084015282810360808401526159078187614a2c565b60a0840195909552505060c0015295945050505050565b8281526040602082015260006142846040830184614a2c565b60c08152600061594a60c08301896156cc565b6020830197909752506001600160a01b039485166040820152929093166060830152608082015260a00152919050565b60408152600061598d6040830185614a2c565b82810360208401526156aa8185614a2c565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60018060a01b03871681528560020b60208201528460020b604082015260c060608201526000615a1d60c0830186614a2c565b6001600160801b039490941660808301525090151560a090910152949350505050565b600080600060608486031215615a5557600080fd5b83516001600160401b03811115615a6b57600080fd5b615a7786828701615077565b9350506020840151915060408401516001600160801b0381168114615a9b57600080fd5b809150509250925092565b600080600060608486031215615abb57600080fd5b83516001600160401b0380821115615ad257600080fd5b615ade87838801615280565b9450602086015191508082111561578657600080fd5b6001600160a01b03858116825284166020820152608060408201819052600090615b20908301856156cc565b8281036060840152612fad8185614a2c565b87815286602082015260e060408201526000615b5160e08301886156cc565b6001600160a01b03871660608401526080830186905282810360a0840152615b7981866156cc565b905082810360c0840152615b8d8185614a2c565b9a9950505050505050505050565b60008251615bad818460208701614b50565b919091019291505056fea264697066735822122011df50cbf6e5dda7d4ddf275008de27810c4c75f970b454eaa98012537320e9864736f6c63430008110033", "libraries": { - "ConverterStrategyBaseLib": "0x0Be4e6b976CFA3F158Fb42F45A4C654F1B4D1Ab1", + "ConverterStrategyBaseLib": "0x2af59Be93d77B391Fea20322407fE46907Bf9D0E", "ConverterStrategyBaseLib2": "0xC92346a144fa75b45b0eDAe966FEAA0E30C82c55", "StrategyLib2": "0x06c875daA1Dc2E27dd7381EB3b6be4F99553a609", - "UniswapV3ConverterStrategyLogicLib": "0x53cb37197219373A95B9662D1C44ede1c554BDdD", - "PairBasedStrategyLib": "0xE5779B35180c1048562c733A7E62f8Fe1d253C41", - "PairBasedStrategyLogicLib": "0xB2dD88095aFe40481C4969f8761DE3D6BC08D222" + "UniswapV3ConverterStrategyLogicLib": "0x4B890495ae196454A8058aA4768bd5f3EE089bEE", + "PairBasedStrategyLib": "0xE0D8b85C7Feb11b26e5A2466931088eC5DE7A703", + "PairBasedStrategyLogicLib": "0x06901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39" }, "devdoc": { "author": "a17", @@ -1479,15 +1479,15 @@ "type": "t_bool" }, { - "astId": 133756, + "astId": 133812, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "state", "offset": 0, "slot": "1", - "type": "t_struct(State)131622_storage" + "type": "t_struct(State)131678_storage" }, { - "astId": 133763, + "astId": 133819, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "__gap", "offset": 0, @@ -1593,7 +1593,7 @@ "label": "contract ITetuConverter", "numberOfBytes": "20" }, - "t_enum(FuseStatus)120846": { + "t_enum(FuseStatus)120905": { "encoding": "inplace", "label": "enum PairBasedStrategyLib.FuseStatus", "numberOfBytes": "1" @@ -1730,20 +1730,20 @@ ], "numberOfBytes": "1696" }, - "t_struct(FuseStateParams)120886_storage": { + "t_struct(FuseStateParams)120945_storage": { "encoding": "inplace", "label": "struct PairBasedStrategyLib.FuseStateParams", "members": [ { - "astId": 120875, + "astId": 120934, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "status", "offset": 0, "slot": "0", - "type": "t_enum(FuseStatus)120846" + "type": "t_enum(FuseStatus)120905" }, { - "astId": 120880, + "astId": 120939, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "thresholds", "offset": 0, @@ -1751,7 +1751,7 @@ "type": "t_array(t_uint256)4_storage" }, { - "astId": 120885, + "astId": 120944, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "__gap", "offset": 0, @@ -1761,12 +1761,12 @@ ], "numberOfBytes": "288" }, - "t_struct(PairState)123065_storage": { + "t_struct(PairState)123124_storage": { "encoding": "inplace", "label": "struct PairBasedStrategyLogicLib.PairState", "members": [ { - "astId": 123024, + "astId": 123083, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "pool", "offset": 0, @@ -1774,7 +1774,7 @@ "type": "t_address" }, { - "astId": 123026, + "astId": 123085, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "strategyProfitHolder", "offset": 0, @@ -1782,7 +1782,7 @@ "type": "t_address" }, { - "astId": 123029, + "astId": 123088, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "tokenA", "offset": 0, @@ -1790,7 +1790,7 @@ "type": "t_address" }, { - "astId": 123032, + "astId": 123091, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "tokenB", "offset": 0, @@ -1798,7 +1798,7 @@ "type": "t_address" }, { - "astId": 123034, + "astId": 123093, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "isStablePool", "offset": 20, @@ -1806,7 +1806,7 @@ "type": "t_bool" }, { - "astId": 123037, + "astId": 123096, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "depositorSwapTokens", "offset": 21, @@ -1814,7 +1814,7 @@ "type": "t_bool" }, { - "astId": 123039, + "astId": 123098, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "tickSpacing", "offset": 22, @@ -1822,7 +1822,7 @@ "type": "t_int24" }, { - "astId": 123041, + "astId": 123100, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "lowerTick", "offset": 25, @@ -1830,7 +1830,7 @@ "type": "t_int24" }, { - "astId": 123043, + "astId": 123102, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "upperTick", "offset": 28, @@ -1838,7 +1838,7 @@ "type": "t_int24" }, { - "astId": 123045, + "astId": 123104, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "rebalanceTickRange", "offset": 0, @@ -1846,7 +1846,7 @@ "type": "t_int24" }, { - "astId": 123047, + "astId": 123106, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "totalLiquidity", "offset": 3, @@ -1854,15 +1854,15 @@ "type": "t_uint128" }, { - "astId": 123051, + "astId": 123110, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "fuseAB", "offset": 0, "slot": "5", - "type": "t_struct(FuseStateParams)120886_storage" + "type": "t_struct(FuseStateParams)120945_storage" }, { - "astId": 123054, + "astId": 123113, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "withdrawDone", "offset": 0, @@ -1870,7 +1870,7 @@ "type": "t_uint256" }, { - "astId": 123057, + "astId": 123116, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "lastRebalanceNoSwap", "offset": 0, @@ -1878,7 +1878,7 @@ "type": "t_uint256" }, { - "astId": 123064, + "astId": 123123, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "__gap", "offset": 0, @@ -1888,20 +1888,20 @@ ], "numberOfBytes": "1568" }, - "t_struct(State)131622_storage": { + "t_struct(State)131678_storage": { "encoding": "inplace", "label": "struct UniswapV3ConverterStrategyLogicLib.State", "members": [ { - "astId": 131616, + "astId": 131672, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "pair", "offset": 0, "slot": "0", - "type": "t_struct(PairState)123065_storage" + "type": "t_struct(PairState)123124_storage" }, { - "astId": 131621, + "astId": 131677, "contract": "contracts/strategies/uniswap/UniswapV3ConverterStrategy.sol:UniswapV3ConverterStrategy", "label": "__gap", "offset": 0, diff --git a/deployments/matic/UniswapV3ConverterStrategyLogicLib.json b/deployments/matic/UniswapV3ConverterStrategyLogicLib.json index dfdc9bfa..d56a541c 100644 --- a/deployments/matic/UniswapV3ConverterStrategyLogicLib.json +++ b/deployments/matic/UniswapV3ConverterStrategyLogicLib.json @@ -1,5 +1,5 @@ { - "address": "0x53cb37197219373A95B9662D1C44ede1c554BDdD", + "address": "0x4B890495ae196454A8058aA4768bd5f3EE089bEE", "abi": [ { "anonymous": false, @@ -163,50 +163,50 @@ "type": "function" } ], - "transactionHash": "0x6c84cb794172c866ca18e3d0cb17a74f0ad4d34d3cc3a70be5de6ff87d145307", + "transactionHash": "0xa6365b99e20ae931a553d54d6ca8a4dae39352470fc956146e710680b5706804", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0x53cb37197219373A95B9662D1C44ede1c554BDdD", - "transactionIndex": 170, + "contractAddress": "0x4B890495ae196454A8058aA4768bd5f3EE089bEE", + "transactionIndex": 39, "gasUsed": "4066127", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0x94cf68f7cc4f8d72f7f3cdd63e76d705eae75c885691c860d451fb090daacdf7", - "transactionHash": "0x6c84cb794172c866ca18e3d0cb17a74f0ad4d34d3cc3a70be5de6ff87d145307", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000040000000000000000200000000000004000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0xb7c088e1b81de763ac64f1d358804b8b0102596e57892327eebe05e96a01b47f", + "transactionHash": "0xa6365b99e20ae931a553d54d6ca8a4dae39352470fc956146e710680b5706804", "logs": [ { - "transactionIndex": 170, - "blockNumber": 54803720, - "transactionHash": "0x6c84cb794172c866ca18e3d0cb17a74f0ad4d34d3cc3a70be5de6ff87d145307", + "transactionIndex": 39, + "blockNumber": 55572353, + "transactionHash": "0xa6365b99e20ae931a553d54d6ca8a4dae39352470fc956146e710680b5706804", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x000000000000000000000000a8b52f02108aa5f4b675bdcc973760022d7c6020" ], - "data": "0x0000000000000000000000000000000000000000000000000015ab2e732b81000000000000000000000000000000000000000000000000026645020f8ae2a68f00000000000000000000000000000000000000000000243749700cb9e3de2b06000000000000000000000000000000000000000000000002662f56e117b7258f0000000000000000000000000000000000000000000024374985b7e85709ac06", - "logIndex": 561, - "blockHash": "0x94cf68f7cc4f8d72f7f3cdd63e76d705eae75c885691c860d451fb090daacdf7" + "data": "0x00000000000000000000000000000000000000000000000005a04a8db6b001fa000000000000000000000000000000000000000000000001d3efd869785b9bf00000000000000000000000000000000000000000000004dcbfac42423b5aea63000000000000000000000000000000000000000000000001ce4f8ddbc1ab99f60000000000000000000000000000000000000000000004dcc54c8ccff20aec5d", + "logIndex": 145, + "blockHash": "0xb7c088e1b81de763ac64f1d358804b8b0102596e57892327eebe05e96a01b47f" } ], - "blockNumber": 54803720, - "cumulativeGasUsed": "23811390", + "blockNumber": 55572353, + "cumulativeGasUsed": "10958975", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 33, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"loss\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"profitToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"coveredByRewards\",\"type\":\"uint256\"}],\"name\":\"Rebalanced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"loss\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"profitToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"coveredByRewards\",\"type\":\"uint256\"}],\"name\":\"RebalancedDebt\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee1\",\"type\":\"uint256\"}],\"name\":\"UniV3FeesClaimed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"rewardTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"calcEarned\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"},{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"},{\"internalType\":\"bool\",\"name\":\"depositorSwapTokens\",\"type\":\"bool\"}],\"name\":\"getEntryDataProportions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"}],\"name\":\"isStablePool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claimRewards(PairBasedStrategyLogicLib.PairState storage)\":{\"returns\":{\"amountsOut\":\"An array containing the amounts of token0 and token1 claimed as rewards.\",\"tokensOut\":\"An array containing tokenA and tokenB.\"}},\"enter(IUniswapV3Pool,int24,int24,uint256[],uint128,bool)\":{\"params\":{\"_depositorSwapTokens\":\"A boolean indicating if need to use token B instead of token A.\",\"amountsDesired_\":\"An array containing the desired amounts of tokens to provide liquidity.\",\"lowerTick\":\"The lower tick value for the pool.\",\"pool\":\"The Uniswap V3 pool to provide liquidity to.\",\"totalLiquidity\":\"The current total liquidity in the pool.\",\"upperTick\":\"The upper tick value for the pool.\"},\"returns\":{\"amountsConsumed\":\"An array containing the consumed amounts for each token in the pool.\",\"liquidityOut\":\"The amount of liquidity added to the pool.\",\"totalLiquidityNew\":\"The updated total liquidity after providing liquidity.\"}},\"exit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"params\":{\"liquidityAmountToExit\":\"The amount of liquidity to exit.\",\"pairState\":\"The State storage object.\"},\"returns\":{\"amountsOut\":\"An array containing the collected amounts for each token in the pool.\"}},\"getEntryDataProportions(IUniswapV3Pool,int24,int24,bool)\":{\"params\":{\"depositorSwapTokens\":\"A boolean indicating if need to use token B instead of token A.\",\"lowerTick\":\"The lower tick of the pool's main range.\",\"pool\":\"Pool instance.\",\"upperTick\":\"The upper tick of the pool's main range.\"},\"returns\":{\"_0\":\"prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\",\"_1\":\"prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\"}},\"getFees(PairBasedStrategyLogicLib.PairState storage)\":{\"params\":{\"pairState\":\"The State storage containing the pool's information.\"},\"returns\":{\"fee0\":\"The fees generated for the first token in the pool.\",\"fee1\":\"The fees generated for the second token in the pool.\"}},\"getPoolReserves(PairBasedStrategyLogicLib.PairState storage)\":{\"params\":{\"pairState\":\"The State storage containing the pool's information.\"},\"returns\":{\"reserves\":\"An array containing the reserve amounts of the contract owned liquidity.\"}},\"initStrategyState(UniswapV3ConverterStrategyLogicLib.State storage,address,address,int24,int24,address,uint256[4])\":{\"params\":{\"fuseThresholds\":\"Fuse thresholds for tokens (stable pool only)\"}},\"isStablePool(IUniswapV3Pool)\":{\"params\":{\"pool\":\"The Uniswap V3 pool.\"},\"returns\":{\"_0\":\"A boolean indicating if the pool is stable.\"}},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter)\":{\"returns\":{\"needRebalance\":\"A boolean indicating if {rebalanceNoSwaps} should be called\"}},\"quoteExit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"params\":{\"liquidityAmountToExit\":\"The amount of liquidity to exit.\"},\"returns\":{\"amountsOut\":\"An array containing the estimated exit amounts for each token in the pool.\"}},\"rebalanceNoSwaps(IConverterStrategyBase.ConverterStrategyBaseState storage,PairBasedStrategyLogicLib.PairState storage,address[2],uint256,uint256,address,bool,mapping(address => uint256) storage)\":{\"params\":{\"checkNeedRebalance_\":\"True if the function should ensure that the rebalance is required\",\"converterLiquidator\":\"[TetuConverter, TetuLiquidator]\",\"totalAssets_\":\"Current value of totalAssets()\"},\"returns\":{\"tokenAmounts\":\"Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\"}},\"withdrawByAggStep(IConverterStrategyBase.ConverterStrategyBaseState storage,address[5],uint256[4],bytes,bytes,PairBasedStrategyLogicLib.PairState storage,mapping(address => uint256) storage)\":{\"params\":{\"addr_\":\"[tokenToSwap, aggregator, controller, converter, splitter]\",\"values_\":\"[amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to proper proportions\",\"tokenAmountsOut\":\"Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimRewards(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Claim rewards from the Uniswap V3 pool.\"},\"enter(IUniswapV3Pool,int24,int24,uint256[],uint128,bool)\":{\"notice\":\"Enter the pool and provide liquidity with desired token amounts.\"},\"exit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"notice\":\"Exit the pool and collect tokens proportional to the liquidity amount to exit.\"},\"getEntryDataProportions(IUniswapV3Pool,int24,int24,bool)\":{\"notice\":\"Calculate proportions of the tokens for entry kind 1\"},\"getFees(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\"},\"getPoolReserves(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Retrieve the reserves of a Uniswap V3 pool managed by this contract.\"},\"getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Get proportion of not-underlying in the pool, [0...1e18] prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\"},\"isStablePool(IUniswapV3Pool)\":{\"notice\":\"Check if the given pool is a stable pool.\"},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter)\":{\"notice\":\"Determine if the strategy needs to be rebalanced.\"},\"quoteExit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"notice\":\"Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\"},\"rebalanceNoSwaps(IConverterStrategyBase.ConverterStrategyBaseState storage,PairBasedStrategyLogicLib.PairState storage,address[2],uint256,uint256,address,bool,mapping(address => uint256) storage)\":{\"notice\":\"Make rebalance without swaps (using borrowing only).\"},\"withdrawByAggStep(IConverterStrategyBase.ConverterStrategyBaseState storage,address[5],uint256[4],bytes,bytes,PairBasedStrategyLogicLib.PairState storage,mapping(address => uint256) storage)\":{\"notice\":\"Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":\"UniswapV3ConverterStrategyLogicLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n\\nlibrary StringLib {\\n\\n /// @dev Inspired by OraclizeAPI's implementation - MIT license\\n /// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n function toString(uint value) external pure returns (string memory) {\\n return _toString(value);\\n }\\n\\n function _toString(uint value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint temp = value;\\n uint digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n function toAsciiString(address x) external pure returns (string memory) {\\n return _toAsciiString(x);\\n }\\n\\n function _toAsciiString(address x) internal pure returns (string memory) {\\n bytes memory s = new bytes(40);\\n for (uint i = 0; i < 20; i++) {\\n bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i)))));\\n bytes1 hi = bytes1(uint8(b) / 16);\\n bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));\\n s[2 * i] = _char(hi);\\n s[2 * i + 1] = _char(lo);\\n }\\n return string(s);\\n }\\n\\n function char(bytes1 b) external pure returns (bytes1 c) {\\n return _char(b);\\n }\\n\\n function _char(bytes1 b) internal pure returns (bytes1 c) {\\n if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);\\n else return bytes1(uint8(b) + 0x57);\\n }\\n\\n}\\n\",\"keccak256\":\"0xe7fef8dd3d994fd08ac32e3eff07f39546cc58dc0101f5fc7c0efebfb4f3f01a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./UniswapV3DebtLib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../../libs/AppErrors.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3ConverterStrategyLogicLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_STABLE = 300;\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE = 500;\\r\\n uint internal constant HARD_WORK_USD_FEE_THRESHOLD = 100;\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event Rebalanced(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event RebalancedDebt(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event UniV3FeesClaimed(uint fee0, uint fee1);\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n\\r\\n struct State {\\r\\n PairBasedStrategyLogicLib.PairState pair;\\r\\n // additional (specific) state\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[10] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceLocal {\\r\\n /// @notice Fuse for token A and token B\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n ITetuConverter converter;\\r\\n IUniswapV3Pool pool;\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool isStablePool;\\r\\n uint[2] liquidationThresholdsAB;\\r\\n\\r\\n bool fuseStatusChangedAB;\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB;\\r\\n\\r\\n uint poolPrice;\\r\\n uint poolPriceAdjustment;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Helpers\\r\\n\\r\\n /// @dev Gets the liquidator swap slippage based on the pool type (stable or volatile).\\r\\n /// @param pool The IUniswapV3Pool instance.\\r\\n /// @return The liquidator swap slippage percentage.\\r\\n function _getLiquidatorSwapSlippage(IUniswapV3Pool pool) internal view returns (uint) {\\r\\n return isStablePool(pool) ? LIQUIDATOR_SWAP_SLIPPAGE_STABLE : LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE;\\r\\n }\\r\\n\\r\\n /// @notice Check if the given pool is a stable pool.\\r\\n /// @param pool The Uniswap V3 pool.\\r\\n /// @return A boolean indicating if the pool is stable.\\r\\n function isStablePool(IUniswapV3Pool pool) public view returns (bool) {\\r\\n return pool.fee() == 100;\\r\\n }\\r\\n\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function initStrategyState(\\r\\n State storage state,\\r\\n address controller_,\\r\\n address pool,\\r\\n int24 tickRange,\\r\\n int24 rebalanceTickRange,\\r\\n address asset_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n require(pool != address(0), AppErrors.ZERO_ADDRESS);\\r\\n address token0 = IUniswapV3Pool(pool).token0();\\r\\n address token1 = IUniswapV3Pool(pool).token1();\\r\\n\\r\\n int24[4] memory tickData;\\r\\n {\\r\\n int24 tickSpacing = UniswapV3Lib.getTickSpacing(IUniswapV3Pool(pool).fee());\\r\\n if (tickRange != 0) {\\r\\n require(tickRange == tickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_TICK_RANGE);\\r\\n require(rebalanceTickRange == rebalanceTickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_REBALANCE_TICK_RANGE);\\r\\n }\\r\\n tickData[0] = tickSpacing;\\r\\n (tickData[1], tickData[2]) = UniswapV3DebtLib.calcTickRange(pool, tickRange, tickSpacing);\\r\\n tickData[3] = rebalanceTickRange;\\r\\n }\\r\\n\\r\\n PairBasedStrategyLogicLib.setInitialDepositorValues(\\r\\n state.pair,\\r\\n [pool, asset_, token0, token1],\\r\\n tickData,\\r\\n isStablePool(IUniswapV3Pool(pool)),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n address liquidator = IController(controller_).liquidator();\\r\\n IERC20(token0).approve(liquidator, type(uint).max);\\r\\n IERC20(token1).approve(liquidator, type(uint).max);\\r\\n }\\r\\n\\r\\n function createSpecificName(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (string memory) {\\r\\n return string(abi.encodePacked(\\r\\n \\\"UniV3 \\\",\\r\\n IERC20Metadata(pairState.tokenA).symbol(),\\r\\n \\\"/\\\",\\r\\n IERC20Metadata(pairState.tokenB).symbol(),\\r\\n \\\"-\\\",\\r\\n StringLib._toString(IUniswapV3Pool(pairState.pool).fee()))\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance.\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(IUniswapV3Pool pool, int24 lowerTick, int24 upperTick, bool depositorSwapTokens) external view returns (uint, uint) {\\r\\n return UniswapV3DebtLib.getEntryDataProportions(pool, lowerTick, upperTick, depositorSwapTokens);\\r\\n }\\r\\n //endregion ------------------------------------------------ Helpers\\r\\n\\r\\n //region ------------------------------------------------ Pool info\\r\\n /// @notice Retrieve the reserves of a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return reserves An array containing the reserve amounts of the contract owned liquidity.\\r\\n function getPoolReserves(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n uint[] memory reserves\\r\\n ) {\\r\\n reserves = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (reserves[0], reserves[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.totalLiquidity\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (reserves[0], reserves[1]) = (reserves[1], reserves[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return fee0 The fees generated for the first token in the pool.\\r\\n /// @return fee1 The fees generated for the second token in the pool.\\r\\n function getFees(PairBasedStrategyLogicLib.PairState storage pairState) public view returns (uint fee0, uint fee1) {\\r\\n UniswapV3Lib.PoolPosition memory position = UniswapV3Lib.PoolPosition(pairState.pool, pairState.lowerTick, pairState.upperTick, pairState.totalLiquidity, address(this));\\r\\n (fee0, fee1) = UniswapV3Lib.getFees(position);\\r\\n }\\r\\n\\r\\n /// @notice Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the estimated exit amounts for each token in the pool.\\r\\n function quoteExit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) public view returns (uint[] memory amountsOut) {\\r\\n amountsOut = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (amountsOut[0], amountsOut[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n liquidityAmountToExit\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Pool info\\r\\n\\r\\n //region ------------------------------------------------ Join the pool\\r\\n /// @notice Enter the pool and provide liquidity with desired token amounts.\\r\\n /// @param pool The Uniswap V3 pool to provide liquidity to.\\r\\n /// @param lowerTick The lower tick value for the pool.\\r\\n /// @param upperTick The upper tick value for the pool.\\r\\n /// @param amountsDesired_ An array containing the desired amounts of tokens to provide liquidity.\\r\\n /// @param totalLiquidity The current total liquidity in the pool.\\r\\n /// @param _depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return amountsConsumed An array containing the consumed amounts for each token in the pool.\\r\\n /// @return liquidityOut The amount of liquidity added to the pool.\\r\\n /// @return totalLiquidityNew The updated total liquidity after providing liquidity.\\r\\n function enter(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint[] memory amountsDesired_,\\r\\n uint128 totalLiquidity,\\r\\n bool _depositorSwapTokens\\r\\n ) external returns (uint[] memory amountsConsumed, uint liquidityOut, uint128 totalLiquidityNew) {\\r\\n amountsConsumed = new uint[](2);\\r\\n\\r\\n if (amountsDesired_[1] > 0) {\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsDesired_[0], amountsDesired_[1]) = (amountsDesired_[1], amountsDesired_[0]);\\r\\n }\\r\\n uint128 newLiquidity;\\r\\n (amountsConsumed[0], amountsConsumed[1], newLiquidity) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, amountsDesired_[0], amountsDesired_[1]);\\r\\n pool.mint(address(this), lowerTick, upperTick, newLiquidity, \\\"\\\");\\r\\n liquidityOut = uint(newLiquidity);\\r\\n totalLiquidityNew = totalLiquidity + newLiquidity;\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsConsumed[0], amountsConsumed[1]) = (amountsConsumed[1], amountsConsumed[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountsConsumed, liquidityOut, totalLiquidityNew);\\r\\n }\\r\\n\\r\\n //endregion ------------------------------------------------ Join the pool\\r\\n\\r\\n //region ------------------------------------------------ Exit from the pool\\r\\n /// @notice Exit the pool and collect tokens proportional to the liquidity amount to exit.\\r\\n /// @param pairState The State storage object.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the collected amounts for each token in the pool.\\r\\n function exit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) external returns (uint[] memory amountsOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n uint128 liquidity = pairState.totalLiquidity;\\r\\n bool _depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n\\r\\n require(liquidity >= liquidityAmountToExit, Uni3StrategyErrors.WRONG_LIQUIDITY);\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n (amountsOut[0], amountsOut[1]) = pool.burn(lowerTick, upperTick, liquidityAmountToExit);\\r\\n\\r\\n // all fees will be collected but not returned in amountsOut\\r\\n pool.collect(address(this), lowerTick, upperTick, type(uint128).max, type(uint128).max);\\r\\n\\r\\n pairState.totalLiquidity = liquidity - liquidityAmountToExit;\\r\\n\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Exit from the pool\\r\\n\\r\\n //region ------------------------------------------------ Claims\\r\\n /// @notice Claim rewards from the Uniswap V3 pool.\\r\\n /// @return tokensOut An array containing tokenA and tokenB.\\r\\n /// @return amountsOut An array containing the amounts of token0 and token1 claimed as rewards.\\r\\n function claimRewards(PairBasedStrategyLogicLib.PairState storage pairState) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n tokensOut = new address[](2);\\r\\n tokensOut[0] = pairState.tokenA;\\r\\n tokensOut[1] = pairState.tokenB;\\r\\n\\r\\n balancesBefore = new uint[](2);\\r\\n for (uint i; i < tokensOut.length; i++) {\\r\\n balancesBefore[i] = IERC20(tokensOut[i]).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n if (pairState.totalLiquidity > 0) {\\r\\n pool.burn(lowerTick, upperTick, 0);\\r\\n (amountsOut[0], amountsOut[1]) = pool.collect(\\r\\n address(this),\\r\\n lowerTick,\\r\\n upperTick,\\r\\n type(uint128).max,\\r\\n type(uint128).max\\r\\n );\\r\\n }\\r\\n\\r\\n emit UniV3FeesClaimed(amountsOut[0], amountsOut[1]);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n\\r\\n for (uint i; i < tokensOut.length; ++i) {\\r\\n uint b = IERC20(tokensOut[i]).balanceOf(strategyProfitHolder);\\r\\n if (b > 0) {\\r\\n IERC20(tokensOut[i]).transferFrom(strategyProfitHolder, address(this), b);\\r\\n amountsOut[i] += b;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n function isReadyToHardWork(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter) external view returns (\\r\\n bool isReady\\r\\n ) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n (uint fee0, uint fee1) = getFees(pairState);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (fee0, fee1) = (fee1, fee0);\\r\\n }\\r\\n\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n address h = pairState.strategyProfitHolder;\\r\\n\\r\\n fee0 += IERC20(tokenA).balanceOf(h);\\r\\n fee1 += IERC20(tokenB).balanceOf(h);\\r\\n\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n\\r\\n uint fee0USD = fee0 * priceA / 1e18;\\r\\n uint fee1USD = fee1 * priceB / 1e18;\\r\\n\\r\\n return fee0USD > HARD_WORK_USD_FEE_THRESHOLD || fee1USD > HARD_WORK_USD_FEE_THRESHOLD;\\r\\n }\\r\\n\\r\\n function sendFeeToProfitHolder(PairBasedStrategyLogicLib.PairState storage pairState, uint fee0, uint fee1) external {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n require(strategyProfitHolder != address (0), Uni3StrategyErrors.ZERO_PROFIT_HOLDER);\\r\\n if (pairState.depositorSwapTokens) {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee1);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee0);\\r\\n } else {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee0);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee1);\\r\\n }\\r\\n emit UniV3FeesClaimed(fee0, fee1);\\r\\n }\\r\\n\\r\\n function calcEarned(address asset, address controller, address[] memory rewardTokens, uint[] memory amounts) external view returns (uint) {\\r\\n ITetuLiquidator liquidator = ITetuLiquidator(IController(controller).liquidator());\\r\\n uint len = rewardTokens.length;\\r\\n uint earned;\\r\\n for (uint i; i < len; ++i) {\\r\\n address token = rewardTokens[i];\\r\\n if (token == asset) {\\r\\n earned += amounts[i];\\r\\n } else {\\r\\n earned += liquidator.getPrice(rewardTokens[i], asset, amounts[i]);\\r\\n }\\r\\n }\\r\\n\\r\\n return earned;\\r\\n }\\r\\n //endregion ------------------------------------------------ Claims\\r\\n\\r\\n //region ------------------------------------------------ Rebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter_) external view returns (\\r\\n bool needRebalance\\r\\n ) {\\r\\n address pool = pairState.pool;\\r\\n // poolPrice should have same decimals as a price from oracle == 18\\r\\n uint poolPriceAdjustment = PairBasedStrategyLib.getPoolPriceAdjustment(IERC20Metadata(pairState.tokenA).decimals());\\r\\n uint poolPrice = UniswapV3Lib.getPrice(pool, pairState.tokenB) * poolPriceAdjustment;\\r\\n (needRebalance, , ) = PairBasedStrategyLogicLib.needStrategyRebalance(\\r\\n pairState,\\r\\n converter_,\\r\\n UniswapV3DebtLib.getCurrentTick(IUniswapV3Pool(pool)),\\r\\n poolPrice\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make rebalance without swaps (using borrowing only).\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param totalAssets_ Current value of totalAssets()\\r\\n /// @param checkNeedRebalance_ True if the function should ensure that the rebalance is required\\r\\n /// @return tokenAmounts Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\\r\\n function rebalanceNoSwaps(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n address[2] calldata converterLiquidator,\\r\\n uint totalAssets_,\\r\\n uint profitToCover,\\r\\n address splitter,\\r\\n bool checkNeedRebalance_,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n RebalanceLocal memory v;\\r\\n _initLocalVars(v, ITetuConverter(converterLiquidator[0]), pairState, liquidityThresholds_);\\r\\n v.poolPrice = UniswapV3Lib.getPrice(address(v.pool), pairState.tokenB) * v.poolPriceAdjustment;\\r\\n bool needRebalance;\\r\\n int24 tick = UniswapV3DebtLib.getCurrentTick(v.pool);\\r\\n (needRebalance,v.fuseStatusChangedAB, v.fuseStatusAB) = PairBasedStrategyLogicLib.needStrategyRebalance(pairState, v.converter, tick, v.poolPrice);\\r\\n\\r\\n // update fuse status if necessary\\r\\n if (needRebalance) {\\r\\n // we assume here, that needRebalance is true if any fuse has changed state, see needStrategyRebalance impl\\r\\n PairBasedStrategyLogicLib.updateFuseStatus(pairState, v.fuseStatusChangedAB, v.fuseStatusAB);\\r\\n }\\r\\n\\r\\n require(!checkNeedRebalance_ || needRebalance, Uni3StrategyErrors.NO_REBALANCE_NEEDED);\\r\\n\\r\\n // rebalancing debt, setting new tick range\\r\\n if (needRebalance) {\\r\\n UniswapV3DebtLib.rebalanceNoSwaps(converterLiquidator, pairState, profitToCover, totalAssets_, splitter, v.liquidationThresholdsAB, tick);\\r\\n\\r\\n uint loss;\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(v.converter, totalAssets_, v.tokenA, v.tokenB, v.liquidationThresholdsAB);\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(csbs, splitter, loss);\\r\\n }\\r\\n emit Rebalanced(loss, profitToCover, 0);\\r\\n }\\r\\n\\r\\n return tokenAmounts;\\r\\n }\\r\\n\\r\\n /// @notice Initialize {v} by state values\\r\\n function _initLocalVars(\\r\\n RebalanceLocal memory v,\\r\\n ITetuConverter converter_,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) internal view {\\r\\n v.pool = IUniswapV3Pool(pairState.pool);\\r\\n v.fuseAB = pairState.fuseAB;\\r\\n v.converter = converter_;\\r\\n v.tokenA = pairState.tokenA;\\r\\n v.tokenB = pairState.tokenB;\\r\\n v.isStablePool = pairState.isStablePool;\\r\\n v.liquidationThresholdsAB[0] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenA]);\\r\\n v.liquidationThresholdsAB[1] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenB]);\\r\\n uint poolPriceDecimals = IERC20Metadata(v.tokenA).decimals();\\r\\n v.poolPriceAdjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n /// @notice Get proportion of not-underlying in the pool, [0...1e18]\\r\\n /// prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\\r\\n function getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage pairState) view external returns (uint) {\\r\\n // get pool proportions\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n bool depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n (int24 newLowerTick, int24 newUpperTick) = UniswapV3DebtLib._calcNewTickRange(pool, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint consumed0, uint consumed1) = UniswapV3DebtLib.getEntryDataProportions(pool, newLowerTick, newUpperTick, depositorSwapTokens);\\r\\n\\r\\n require(consumed0 + consumed1 > 0, AppErrors.ZERO_VALUE);\\r\\n return consumed1 * 1e18 / (consumed0 + consumed1);\\r\\n }\\r\\n //endregion ------------------------------------------------ Rebalance\\r\\n\\r\\n //region ------------------------------------------------ WithdrawByAgg\\r\\n /// @notice Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmountsOut Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\\r\\n function withdrawByAggStep(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint entryToPool = values_[3];\\r\\n address[2] memory tokens = [pairState.tokenA, pairState.tokenB];\\r\\n\\r\\n // Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n uint[] memory tokenAmounts;\\r\\n uint loss;\\r\\n (completed, tokenAmounts, loss) = PairBasedStrategyLogicLib.withdrawByAggStep(\\r\\n addr_,\\r\\n values_,\\r\\n swapData,\\r\\n planEntryData,\\r\\n tokens,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // cover loss\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(\\r\\n csbs,\\r\\n addr_[4],\\r\\n loss\\r\\n );\\r\\n }\\r\\n emit RebalancedDebt(loss, values_[1], 0);\\r\\n\\r\\n if (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED\\r\\n || (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED && completed)\\r\\n ) {\\r\\n // We are going to enter to the pool: update lowerTick and upperTick, initialize tokenAmountsOut\\r\\n (pairState.lowerTick, pairState.upperTick) = UniswapV3DebtLib._calcNewTickRange(\\r\\n IUniswapV3Pool(pairState.pool),\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing\\r\\n );\\r\\n tokenAmountsOut = tokenAmounts;\\r\\n }\\r\\n return (completed, tokenAmountsOut); // hide warning\\r\\n }\\r\\n //endregion ------------------------------------------------ WithdrawByAgg\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4430a5a110ff7a45e1cc8930b9ec640e7f97305de498cd5647290ee1f512fa31\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x61489161003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c80637269cb3a116100ac578063a7aced091161007b578063a7aced0914610296578063adc43434146102a9578063af316733146102c9578063b6fda813146102f8578063bd85be291461031857600080fd5b80637269cb3a1461021357806380089367146102265780638fb5468e14610255578063911ec0531461026857600080fd5b80632b25a6cf116100e85780632b25a6cf1461019e57806334d2ec3d146101c05780633ae60bcb146101d357806354747e5b1461020057600080fd5b80630dc528a71461011a5780631749995614610147578063233545261461015a57806328f0aec41461017d575b600080fd5b61012d6101283660046136e0565b610338565b604080519283526020830191909152015b60405180910390f35b61012d61015536600461373c565b610354565b61016d610168366004613755565b610468565b604051901515815260200161013e565b61019061018b36600461373c565b6106f1565b60405190815260200161013e565b8180156101aa57600080fd5b506101be6101b9366004613785565b6107e8565b005b6101906101ce366004613885565b6108f1565b8180156101df57600080fd5b506101f36101ee366004613982565b610ab3565b60405161013e91906139e2565b61016d61020e3660046139fc565b610d69565b61016d610221366004613755565b610ddc565b81801561023257600080fd5b50610246610241366004613a19565b611093565b60405161013e93929190613ab3565b6101f361026336600461373c565b611387565b81801561027457600080fd5b50610288610283366004613b6e565b611591565b60405161013e929190613c1c565b6101f36102a4366004613982565b6117d8565b8180156102b557600080fd5b506101be6102c4366004613c37565b6119cf565b8180156102d557600080fd5b506102e96102e436600461373c565b611f6b565b60405161013e93929190613cc2565b81801561030457600080fd5b506101f3610313366004613d37565b612518565b61032b61032636600461373c565b6129f9565b60405161013e9190613e07565b60008061034786868686612b8a565b9150915094509492505050565b6040805160a08101825282546001600160a01b0390811682526003840154600160c81b8104600290810b60208501908152600160e01b909204810b848601908152600480880154630100000090046001600160801b0390811660608801908152306080890190815298516352bb7e6960e01b815288518816938101939093529451840b6024830152915190920b604483015291519091166064820152925116608483015260009182919073D398438a52fD230195861b9Af0B4Ab8e9b0006F2906352bb7e699060a4016040805180830381865af4158015610439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045d9190613e1a565b909590945092505050565b600080600061047685610354565b60038701549193509150600160a81b900460ff161561049157905b6002850154600386015460018701546040516370a0823160e01b81526001600160a01b0393841693928316929091169083906370a08231906104d7908490600401613e3e565b602060405180830381865afa1580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105189190613e52565b6105229086613e81565b6040516370a0823160e01b81529095506001600160a01b038316906370a0823190610551908490600401613e3e565b602060405180830381865afa15801561056e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105929190613e52565b61059c9085613e81565b935060006105a988612e57565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b81526004016105d99190613e3e565b602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a9190613e52565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b815260040161064a9190613e3e565b602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190613e52565b90506000670de0b6b3a76400006106a2848b613e94565b6106ac9190613ec1565b90506000670de0b6b3a76400006106c3848b613e94565b6106cd9190613ec1565b905060648211806106de5750606481115b9a50505050505050505050505b92915050565b805460038201546000916001600160a01b03169060ff600160a81b8204169083908190610740908590600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b9150915060008061075386858588612b8a565b909250905060006107648284613e81565b116040518060400160405280601081526020016f54532d3234207a65726f2076616c756560801b815250906107b55760405162461bcd60e51b81526004016107ac9190613e07565b60405180910390fd5b506107c08183613e81565b6107d282670de0b6b3a7640000613e94565b6107dc9190613ec1565b98975050505050505050565b6001830154604080516060810190915260228082526001600160a01b039092169182151591906148186020830139906108345760405162461bcd60e51b81526004016107ac9190613e07565b506003840154600160a81b900460ff1615610880576002840154610862906001600160a01b03168284612f46565b600384015461087b906001600160a01b03168285612f46565b6108b2565b6002840154610899906001600160a01b03168285612f46565b60038401546108b2906001600160a01b03168284612f46565b60408051848152602081018490527fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89910160405180910390a150505050565b600080846001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613ed5565b84519091506000805b82811015610aa557600087828151811061097b5761097b613ef2565b60200260200101519050896001600160a01b0316816001600160a01b0316036109ca578682815181106109b0576109b0613ef2565b6020026020010151836109c39190613e81565b9250610a94565b846001600160a01b031663a9dd14d68984815181106109eb576109eb613ef2565b60200260200101518c8a8681518110610a0657610a06613ef2565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015610a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a879190613e52565b610a919084613e81565b92505b50610a9e81613f08565b905061095f565b50925050505b949350505050565b8154600383015460048401546040805180820190915260158152745533532d372057726f6e67206c697175696469747960581b60208201526060936001600160a01b031692600160c81b8104600290810b93600160e01b830490910b926001600160801b03630100000090920482169260ff600160a81b90910416918816831015610b515760405162461bcd60e51b81526004016107ac9190613e07565b5060408051600280825260608201835290916020830190803683370190505060405163a34123a760e01b8152600286810b600483015285900b60248201526001600160801b03891660448201529096506001600160a01b0386169063a34123a79060640160408051808303816000875af1158015610bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf79190613e1a565b87600081518110610c0a57610c0a613ef2565b6020026020010188600181518110610c2457610c24613ef2565b6020908102919091010191909152526040516309e3d67b60e31b81526001600160a01b03861690634f1eb3d890610c6e903090889088906001600160801b03908190600401613f21565b60408051808303816000875af1158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190613f5e565b50610cbd90508783613f8d565b8860040160036101000a8154816001600160801b0302191690836001600160801b031602179055508015610d5e5785600181518110610cfe57610cfe613ef2565b602002602001015186600081518110610d1957610d19613ef2565b602002602001015187600081518110610d3457610d34613ef2565b6020026020010188600181518110610d4e57610d4e613ef2565b6020908102919091010191909152525b505050505092915050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190613fad565b62ffffff166064149050919050565b815460028301546040805163313ce56760e01b815290516000936001600160a01b0390811693859373E5779B35180c1048562c733A7E62f8Fe1d253C419363556ce728939092169163313ce567916004808201926020929091908290030181865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190613fe8565b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865af4158015610eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed59190613e52565b6003860154604051635620c32d60e11b81526001600160a01b0380861660048301529091166024820152909150600090829073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190613e52565b610f719190613e94565b905073B2dD88095aFe40481C4969f8761DE3D6BC08D2226351265e89878773536d15b1F898f8648Cb3633F4531B133A69c7e906317b13c95886040518263ffffffff1660e01b8152600401610fc69190613e3e565b602060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614003565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015260020b604482015260648101849052608401606060405180830381865af4158015611062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110869190614020565b5090979650505050505050565b604080516002808252606082810190935260009182918160200160208202803683370190505092506000866001815181106110d0576110d0613ef2565b6020026020010151111561137b57831561115757856001815181106110f7576110f7613ef2565b60200260200101518660008151811061111257611112613ef2565b60200260200101518760008151811061112d5761112d613ef2565b602002602001018860018151811061114757611147613ef2565b6020908102919091010191909152525b600073D398438a52fD230195861b9Af0B4Ab8e9b0006F26317c22c3c8b8b8b8b60008151811061118957611189613ef2565b60200260200101518c6001815181106111a4576111a4613ef2565b60200260200101516040518663ffffffff1660e01b81526004016111cc959493929190614071565b606060405180830381865af41580156111e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120d91906140a5565b8660008151811061122057611220613ef2565b602002602001018760018151811061123a5761123a613ef2565b6020908102919091010192909252919052604051633c8a7d8d60e01b815230600482015260028b810b60248301528a900b60448201526001600160801b038216606482015260a06084820152600060a48201529091506001600160a01b038b1690633c8a7d8d9060c40160408051808303816000875af11580156112c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e69190613e1a565b50506001600160801b03811692506112fe81876140d3565b91508415611379578360018151811061131957611319613ef2565b60200260200101518460008151811061133457611334613ef2565b60200260200101518560008151811061134f5761134f613ef2565b602002602001018660018151811061136957611369613ef2565b6020908102919091010191909152525b505b96509650969350505050565b60408051600280825260608083018452926020830190803683375050835460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa1580156113f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114169190614105565b505050506003860154600480880154604051630544f36560e31b815295965073D398438a52fD230195861b9Af0B4Ab8e9b0006F295632a279b28955061148894508793600160c81b8104600290810b94600160e01b909204900b92630100000090046001600160801b03169101614194565b6040805180830381865af41580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190613e1a565b836000815181106114db576114db613ef2565b60200260200101846001815181106114f5576114f5613ef2565b6020908102919091010191909152526003830154600160a81b900460ff161561158b578160018151811061152b5761152b613ef2565b60200260200101518260008151811061154657611546613ef2565b60200260200101518360008151811061156157611561613ef2565b602002602001018460018151811061157b5761157b613ef2565b6020908102919091010191909152525b50919050565b60408051808201825260028401546001600160a01b0390811682526003850154166020820152905163bd13c52960e01b81526000916060918883013591908390859073B2dD88095aFe40481C4969f8761DE3D6BC08D2229063bd13c52990611607908f908f908f908f908a908f906004016141d0565b600060405180830381865af4158015611624573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164c91908101906142e2565b9197509250905080156116ef5773C92346a144fa75b45b0eDAe966FEAA0E30C82c556326eadaa38e8e600460200201602081019061168a91906139fc565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044810184905260640160006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505b6040805182815260208d8101359082015260008183015290517f3715d08a7dcc9d792a5a426f62429b9f889a7b140004f9f85190a48485695cf19181900360600190a1600184148061174957506002841480156117495750855b156117c85787546003890154611789916001600160a01b031690600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b60038a01805465ffffffffffff60c81b1916600160e01b62ffffff9384160262ffffff60c81b191617600160c81b939092169290920217905590935083905b5050505097509795505050505050565b60408051600280825260608083018452926020830190803683375050845460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa158015611843573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118679190614105565b5050506003880154604051630544f36560e31b815294955073D398438a52fD230195861b9Af0B4Ab8e9b0006F294632a279b2894506118c59350869250600160c81b8204600290810b92600160e01b9004900b908990600401614194565b6040805180830381865af41580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190613e1a565b8360008151811061191857611918613ef2565b602002602001018460018151811061193257611932613ef2565b6020908102919091010191909152526003840154600160a81b900460ff16156119c8578160018151811061196857611968613ef2565b60200260200101518260008151811061198357611983613ef2565b60200260200101518360008151811061199e5761199e613ef2565b60200260200101846001815181106119b8576119b8613ef2565b6020908102919091010191909152525b5092915050565b60408051808201909152601181527054532d31207a65726f206164647265737360781b60208201526001600160a01b038616611a1e5760405162461bcd60e51b81526004016107ac9190613e07565b506000856001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190613ed5565b90506000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190613ed5565b9050611af36135dc565b600073D398438a52fD230195861b9Af0B4Ab8e9b0006F263ea8668158a6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190613fad565b6040516001600160e01b031960e084901b16815262ffffff9091166004820152602401602060405180830381865af4158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd59190614003565b90508760020b600014611caa5780611bed818a61433b565b611bf79190614375565b60020b8860020b146040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525090611c535760405162461bcd60e51b81526004016107ac9190613e07565b5080611c5f818961433b565b611c699190614375565b60020b8760020b1460405180606001604052806022815260200161483a6022913990611ca85760405162461bcd60e51b81526004016107ac9190613e07565b505b600281810b80845260405163362ad1e560e11b81526001600160a01b038c166004820152918a900b6024830152604482015273536d15b1F898f8648Cb3633F4531B133A69c7e9090636c55a3ca906064016040805180830381865af4158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614395565b600290810b60408086019190915291810b6020808601919091529089900b60608086019190915282516080810184526001600160a01b038d811682528a811693820193909352878316938101939093529085169082015273B2dD88095aFe40481C4969f8761DE3D6BC08D222915063b8b4a449908c9084611dbb8d610d69565b896040518663ffffffff1660e01b8152600401611ddc9594939291906143c4565b60006040518083038186803b158015611df457600080fd5b505af4158015611e08573d6000803e3d6000fd5b505050506000896001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e709190613ed5565b60405163095ea7b360e01b81526001600160a01b03808316600483015260001960248301529192509085169063095ea7b3906044016020604051808303816000875af1158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190614441565b5060405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015284169063095ea7b3906044016020604051808303816000875af1158015611f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5d9190614441565b505050505050505050505050565b6001810154815460038301546040805160028082526060808301845295869586956001600160a01b03928316959290911693600160c81b8204840b93600160e01b909204820b92909190602083019080368337505050600289015481519198506001600160a01b0316908890600090611fe657611fe6613ef2565b6001600160a01b039283166020918202929092010152600389015488519116908890600190811061201957612019613ef2565b6001600160a01b039290921660209283029190910182015260408051600280825260608201835290929091908301908036833701905050945060005b87518110156121135787818151811061207057612070613ef2565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120a39190613e3e565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e49190613e52565b8682815181106120f6576120f6613ef2565b60209081029190910101528061210b81613f08565b915050612055565b506040805160028082526060820183529091602083019080368337019050506004890154909650630100000090046001600160801b03161561229f5760405163a34123a760e01b8152600283810b600483015282900b6024820152600060448201526001600160a01b0384169063a34123a79060640160408051808303816000875af11580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613e1a565b50506040516309e3d67b60e31b81526001600160a01b03841690634f1eb3d890612208903090869086906001600160801b03908190600401613f21565b60408051808303816000875af1158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a9190613f5e565b816001600160801b03169150806001600160801b031690508760008151811061227557612275613ef2565b602002602001018860018151811061228f5761228f613ef2565b6020908102919091010191909152525b7fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89866000815181106122d3576122d3613ef2565b6020026020010151876001815181106122ee576122ee613ef2565b602002602001015160405161230d929190918252602082015260400190565b60405180910390a16003880154600160a81b900460ff161561239c578560018151811061233c5761233c613ef2565b60200260200101518660008151811061235757612357613ef2565b60200260200101518760008151811061237257612372613ef2565b602002602001018860018151811061238c5761238c613ef2565b6020908102919091010191909152525b60005b875181101561250c5760008882815181106123bc576123bc613ef2565b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016123ef9190613e3e565b602060405180830381865afa15801561240c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124309190613e52565b905080156124fb5788828151811061244a5761244a613ef2565b60209081029190910101516040516323b872dd60e01b81526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf9190614441565b50808883815181106124e3576124e3613ef2565b602002602001018181516124f79190613e81565b9052505b5061250581613f08565b905061239f565b50505050509193909250565b60606125226135fa565b61253a8161253360208b018b6139fc565b8b86612f9d565b61014081015160408083015160038c01549151635620c32d60e11b81526001600160a01b0391821660048201529116602482015273D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af41580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190613e52565b6125d89190613e94565b61012082015260408082015190516317b13c9560e01b8152600091829173536d15b1F898f8648Cb3633F4531B133A69c7e90916317b13c959161261e9190600401613e3e565b602060405180830381865af415801561263b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265f9190614003565b60208401516101208501516040516351265e8960e01b8152600481018f90526001600160a01b039092166024830152600283900b6044830152606482015290915073B2dD88095aFe40481C4969f8761DE3D6BC08D222906351265e8990608401606060405180830381865af41580156126dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127009190614020565b8560e001866101000182600381111561271b5761271b61445e565b600381111561272c5761272c61445e565b905291151590915250915081156127b25773B2dD88095aFe40481C4969f8761DE3D6BC08D222634aa009158c8560e001518661010001516040518463ffffffff1660e01b815260040161278193929190614474565b60006040518083038186803b15801561279957600080fd5b505af41580156127ad573d6000803e3d6000fd5b505050505b8515806127bc5750815b6040518060400160405280601981526020017f5533532d39204e6f20726562616c616e6365206e656564656400000000000000815250906128105760405162461bcd60e51b81526004016107ac9190613e07565b5081156129ea5773536d15b1F898f8648Cb3633F4531B133A69c7e9063e4ee4bf78b8d8b8d8c8960c00151886040518863ffffffff1660e01b815260040161285e97969594939291906144d8565b60006040518083038186803b15801561287657600080fd5b505af415801561288a573d6000803e3d6000fd5b50505050600073C92346a144fa75b45b0eDAe966FEAA0E30C82c5563ac2a37d685602001518c876060015188608001518960c001516040518663ffffffff1660e01b81526004016128df95949392919061455e565b600060405180830381865af41580156128fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129249190810190614592565b9550905080156129a8576040516326eadaa360e01b8152600481018e90526001600160a01b03891660248201526044810182905273C92346a144fa75b45b0eDAe966FEAA0E30C82c55906326eadaa39060640160006040518083038186803b15801561298f57600080fd5b505af41580156129a3573d6000803e3d6000fd5b505050505b60408051828152602081018b905260008183015290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a1505b50505098975050505050505050565b6002810154604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015612a45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a6d91908101906145d8565b8260030160009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ac2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aea91908101906145d8565b83546040805163ddca3f4360e01b81529051612b62926001600160a01b03169163ddca3f439160048083019260209291908290030181865afa158015612b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b589190613fad565b62ffffff16613194565b604051602001612b749392919061464e565b6040516020818303038152906040529050919050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf19190613ed5565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613e52565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190613fe8565b60ff169050816000612cf483600a6147a3565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015290915081612d3c5760405162461bcd60e51b81526004016107ac9190613e07565b5060008073D398438a52fD230195861b9Af0B4Ab8e9b0006F26317c22c3c8e8e8e88886040518663ffffffff1660e01b8152600401612d7f959493929190614071565b606060405180830381865af4158015612d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc091906140a5565b509150915089612e0957612ddc82670de0b6b3a7640000613e94565b8387612df084670de0b6b3a7640000613e94565b612dfa9190613e94565b612e049190613ec1565b612e43565b8286612e1d83670de0b6b3a7640000613e94565b612e279190613e94565b612e319190613ec1565b612e4383670de0b6b3a7640000613e94565b985098505050505050505094509492505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebb9190613ed5565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106eb9190613ed5565b6000806000612f2a87613294565b9050612f3881878787613305565b925092505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612f989084906133cf565b505050565b81546001600160a01b0316604080860191909152805160608101909152600583018054829060ff166003811115612fd657612fd661445e565b6003811115612fe757612fe761445e565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161300757505050918352505060408051608081019182905260209092019190600584019060049082845b815481526020019060010190808311613040575050509190925250505084526001600160a01b03838116602080870191909152600284015482166060870181905260038501549283166080880152600160a01b90920460ff16151560a0870152600091825282905260409020546130b6906134a1565b60c08501515260808401516001600160a01b03166000908152602082905260409020546130e2906134a1565b60c08501516001602002018181525050600084606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315a9190613fe8565b60ff1690506012811061316e576001613184565b6131798160126147af565b61318490600a6147a3565b6101409095019490945250505050565b6060816000036131bb5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156131e557806131cf81613f08565b91506131de9050600a83613ec1565b91506131bf565b6000816001600160401b038111156131ff576131ff6137b1565b6040519080825280601f01601f191660200182016040528015613229576020820181803683370190505b5090505b8415610aab5761323e6001836147af565b915061324b600a866147c2565b613256906030613e81565b60f81b81838151811061326b5761326b613ef2565b60200101906001600160f81b031916908160001a90535061328d600a86613ec1565b945061322d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f89190614105565b5093979650505050505050565b6000808061331386866147d6565b905060008460020b8260020b146133345761332f60028361433b565b613337565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073B2dD88095aFe40481C4969f8761DE3D6BC08D2229063cd8e20e7906064016040805180830381865af415801561339c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c09190614395565b93509350505094509492505050565b6000613424826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134b99092919063ffffffff16565b805190915015612f9857808060200190518101906134429190614441565b612f985760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ac565b600081156134af57816106eb565b620186a092915050565b6060610aab848460008585600080866001600160a01b031685876040516134e091906147fb565b60006040518083038185875af1925050503d806000811461351d576040519150601f19603f3d011682016040523d82523d6000602084013e613522565b606091505b50915091506135338783838761353e565b979650505050505050565b606083156135ad5782516000036135a6576001600160a01b0385163b6135a65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107ac565b5081610aab565b610aab83838151156135c25781518083602001fd5b8060405162461bcd60e51b81526004016107ac9190613e07565b60405180608001604052806004906020820280368337509192915050565b60405180610160016040528061360e613660565b815260006020820181905260408201819052606082018190526080820181905260a082015260c00161363e61368d565b8152600060208201819052604082018190526060820181905260809091015290565b6040805160608101909152806000815260200161367b6135dc565b81526020016136886135dc565b905290565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146136c057600080fd5b50565b8060020b81146136c057600080fd5b80151581146136c057600080fd5b600080600080608085870312156136f657600080fd5b8435613701816136ab565b93506020850135613711816136c3565b92506040850135613721816136c3565b91506060850135613731816136d2565b939692955090935050565b60006020828403121561374e57600080fd5b5035919050565b6000806040838503121561376857600080fd5b82359150602083013561377a816136ab565b809150509250929050565b60008060006060848603121561379a57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137ef576137ef6137b1565b604052919050565b60006001600160401b03821115613810576138106137b1565b5060051b60200190565b600082601f83011261382b57600080fd5b8135602061384061383b836137f7565b6137c7565b82815260059290921b8401810191818101908684111561385f57600080fd5b8286015b8481101561387a5780358352918301918301613863565b509695505050505050565b6000806000806080858703121561389b57600080fd5b84356138a6816136ab565b93506020858101356138b7816136ab565b935060408601356001600160401b03808211156138d357600080fd5b818801915088601f8301126138e757600080fd5b81356138f561383b826137f7565b81815260059190911b8301840190848101908b83111561391457600080fd5b938501935b8285101561393b57843561392c816136ab565b82529385019390850190613919565b96505050606088013592508083111561395357600080fd5b50506139618782880161381a565b91505092959194509250565b6001600160801b03811681146136c057600080fd5b6000806040838503121561399557600080fd5b82359150602083013561377a8161396d565b600081518084526020808501945080840160005b838110156139d7578151875295820195908201906001016139bb565b509495945050505050565b6020815260006139f560208301846139a7565b9392505050565b600060208284031215613a0e57600080fd5b81356139f5816136ab565b60008060008060008060c08789031215613a3257600080fd5b8635613a3d816136ab565b95506020870135613a4d816136c3565b94506040870135613a5d816136c3565b935060608701356001600160401b03811115613a7857600080fd5b613a8489828a0161381a565b9350506080870135613a958161396d565b915060a0870135613aa5816136d2565b809150509295509295509295565b606081526000613ac660608301866139a7565b90508360208301526001600160801b0383166040830152949350505050565b80608081018310156106eb57600080fd5b60006001600160401b03821115613b0f57613b0f6137b1565b50601f01601f191660200190565b600082601f830112613b2e57600080fd5b8135613b3c61383b82613af6565b818152846020838601011115613b5157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060006101c0888a031215613b8a57600080fd5b8735965060c0880189811115613b9f57600080fd5b602089019650613baf8a82613ae5565b9550506101408801356001600160401b0380821115613bcd57600080fd5b613bd98b838c01613b1d565b95506101608a0135915080821115613bf057600080fd5b50613bfd8a828b01613b1d565b93505061018088013591506101a0880135905092959891949750929550565b8215158152604060208201526000610aab60408301846139a7565b6000806000806000806000610140888a031215613c5357600080fd5b873596506020880135613c65816136ab565b95506040880135613c75816136ab565b94506060880135613c85816136c3565b93506080880135613c95816136c3565b925060a0880135613ca5816136ab565b9150613cb48960c08a01613ae5565b905092959891949750929550565b606080825284519082018190526000906020906080840190828801845b82811015613d045781516001600160a01b031684529284019290840190600101613cdf565b50505083810382850152613d1881876139a7565b9150508281036040840152613d2d81856139a7565b9695505050505050565b600080600080600080600080610120898b031215613d5457600080fd5b8835975060208901359650608089018a811115613d7057600080fd5b60408a01965035945060a0890135935060c0890135613d8e816136ab565b925060e0890135613d9e816136d2565b8092505061010089013590509295985092959890939650565b60005b83811015613dd2578181015183820152602001613dba565b50506000910152565b60008151808452613df3816020860160208601613db7565b601f01601f19169290920160200192915050565b6020815260006139f56020830184613ddb565b60008060408385031215613e2d57600080fd5b505080516020909101519092909150565b6001600160a01b0391909116815260200190565b600060208284031215613e6457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106eb576106eb613e6b565b80820281158282048414176106eb576106eb613e6b565b634e487b7160e01b600052601260045260246000fd5b600082613ed057613ed0613eab565b500490565b600060208284031215613ee757600080fd5b81516139f5816136ab565b634e487b7160e01b600052603260045260246000fd5b600060018201613f1a57613f1a613e6b565b5060010190565b6001600160a01b03959095168552600293840b60208601529190920b60408401526001600160801b03918216606084015216608082015260a00190565b60008060408385031215613f7157600080fd5b8251613f7c8161396d565b602084015190925061377a8161396d565b6001600160801b038281168282160390808211156119c8576119c8613e6b565b600060208284031215613fbf57600080fd5b815162ffffff811681146139f557600080fd5b805160ff81168114613fe357600080fd5b919050565b600060208284031215613ffa57600080fd5b6139f582613fd2565b60006020828403121561401557600080fd5b81516139f5816136c3565b60008060006060848603121561403557600080fd5b8351614040816136d2565b6020850151909350614051816136d2565b60408501519092506004811061406657600080fd5b809150509250925092565b6001600160a01b03959095168552600293840b60208601529190920b60408401526060830191909152608082015260a00190565b6000806000606084860312156140ba57600080fd5b835192506020840151915060408401516140668161396d565b6001600160801b038181168382160190808211156119c8576119c8613e6b565b805161ffff81168114613fe357600080fd5b600080600080600080600060e0888a03121561412057600080fd5b875161412b816136ab565b602089015190975061413c816136c3565b955061414a604089016140f3565b9450614158606089016140f3565b9350614166608089016140f3565b925061417460a08901613fd2565b915060c0880151614184816136d2565b8091505092959891949750929550565b6001600160a01b03949094168452600292830b6020850152910b60408301526001600160801b0316606082015260800190565b60808183375050565b60006101c08289835b600581101561420b5781356141ed816136ab565b6001600160a01b0316835260209283019291909101906001016141d9565b50505060808860a08501378061012084015261422981840188613ddb565b905082810361014084015261423e8187613ddb565b91505061016082018460005b60028110156142725781516001600160a01b031683526020928301929091019060010161424a565b505050826101a0830152979650505050505050565b600082601f83011261429857600080fd5b815160206142a861383b836137f7565b82815260059290921b840181019181810190868411156142c757600080fd5b8286015b8481101561387a57805183529183019183016142cb565b6000806000606084860312156142f757600080fd5b8351614302816136d2565b60208501519093506001600160401b0381111561431e57600080fd5b61432a86828701614287565b925050604084015190509250925092565b60008160020b8360020b8061435257614352613eab565b627fffff1982146000198214161561436c5761436c613e6b565b90059392505050565b60008260020b8260020b028060020b91508082146119c8576119c8613e6b565b600080604083850312156143a857600080fd5b82516143b3816136c3565b602084015190925061377a816136c3565b8581526101c0810160208083018760005b60048110156143fb5781516001600160a01b0316835291830191908301906001016143d5565b50505060a083018660005b600481101561442657815160020b83529183019190830190600101614406565b50505050831515610120830152613d2d6101408301846141c7565b60006020828403121561445357600080fd5b81516139f5816136d2565b634e487b7160e01b600052602160045260246000fd5b838152821515602082015260608101600483106144a157634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b8060005b60028110156144d25781518452602093840193909101906001016144b3565b50505050565b6101208101818960005b60028110156145145781356144f6816136ab565b6001600160a01b0316835260209283019291909101906001016144e2565b5050506040820188905260608201879052608082018690526001600160a01b03851660a083015261454860c08301856144af565b8260020b61010083015298975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c08101613d2d60808301846144af565b600080604083850312156145a557600080fd5b8251915060208301516001600160401b038111156145c257600080fd5b6145ce85828601614287565b9150509250929050565b6000602082840312156145ea57600080fd5b81516001600160401b0381111561460057600080fd5b8201601f8101841361461157600080fd5b805161461f61383b82613af6565b81815285602083850101111561463457600080fd5b614645826020830160208601613db7565b95945050505050565b6502ab734ab19960d51b81526000845161466f816006850160208901613db7565b602f60f81b6006918401918201528451614690816007840160208901613db7565b602d60f81b6007929091019182015283516146b2816008840160208801613db7565b0160080195945050505050565b600181815b808511156146fa5781600019048211156146e0576146e0613e6b565b808516156146ed57918102915b93841c93908002906146c4565b509250929050565b600082614711575060016106eb565b8161471e575060006106eb565b8160018114614734576002811461473e5761475a565b60019150506106eb565b60ff84111561474f5761474f613e6b565b50506001821b6106eb565b5060208310610133831016604e8410600b841016171561477d575081810a6106eb565b61478783836146bf565b806000190482111561479b5761479b613e6b565b029392505050565b60006139f58383614702565b818103818111156106eb576106eb613e6b565b6000826147d1576147d1613eab565b500690565b600282810b9082900b03627fffff198112627fffff821317156106eb576106eb613e6b565b6000825161480d818460208701613db7565b919091019291505056fe5533532d3133205a65726f2073747261746567792070726f66697420686f6c6465725042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a26469706673582212200343d57e33cce12f7e7959de066953f2dc0fe1356e55d91afd9e2cbb9643e27a64736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c80637269cb3a116100ac578063a7aced091161007b578063a7aced0914610296578063adc43434146102a9578063af316733146102c9578063b6fda813146102f8578063bd85be291461031857600080fd5b80637269cb3a1461021357806380089367146102265780638fb5468e14610255578063911ec0531461026857600080fd5b80632b25a6cf116100e85780632b25a6cf1461019e57806334d2ec3d146101c05780633ae60bcb146101d357806354747e5b1461020057600080fd5b80630dc528a71461011a5780631749995614610147578063233545261461015a57806328f0aec41461017d575b600080fd5b61012d6101283660046136e0565b610338565b604080519283526020830191909152015b60405180910390f35b61012d61015536600461373c565b610354565b61016d610168366004613755565b610468565b604051901515815260200161013e565b61019061018b36600461373c565b6106f1565b60405190815260200161013e565b8180156101aa57600080fd5b506101be6101b9366004613785565b6107e8565b005b6101906101ce366004613885565b6108f1565b8180156101df57600080fd5b506101f36101ee366004613982565b610ab3565b60405161013e91906139e2565b61016d61020e3660046139fc565b610d69565b61016d610221366004613755565b610ddc565b81801561023257600080fd5b50610246610241366004613a19565b611093565b60405161013e93929190613ab3565b6101f361026336600461373c565b611387565b81801561027457600080fd5b50610288610283366004613b6e565b611591565b60405161013e929190613c1c565b6101f36102a4366004613982565b6117d8565b8180156102b557600080fd5b506101be6102c4366004613c37565b6119cf565b8180156102d557600080fd5b506102e96102e436600461373c565b611f6b565b60405161013e93929190613cc2565b81801561030457600080fd5b506101f3610313366004613d37565b612518565b61032b61032636600461373c565b6129f9565b60405161013e9190613e07565b60008061034786868686612b8a565b9150915094509492505050565b6040805160a08101825282546001600160a01b0390811682526003840154600160c81b8104600290810b60208501908152600160e01b909204810b848601908152600480880154630100000090046001600160801b0390811660608801908152306080890190815298516352bb7e6960e01b815288518816938101939093529451840b6024830152915190920b604483015291519091166064820152925116608483015260009182919073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__906352bb7e699060a4016040805180830381865af4158015610439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045d9190613e1a565b909590945092505050565b600080600061047685610354565b60038701549193509150600160a81b900460ff161561049157905b6002850154600386015460018701546040516370a0823160e01b81526001600160a01b0393841693928316929091169083906370a08231906104d7908490600401613e3e565b602060405180830381865afa1580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105189190613e52565b6105229086613e81565b6040516370a0823160e01b81529095506001600160a01b038316906370a0823190610551908490600401613e3e565b602060405180830381865afa15801561056e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105929190613e52565b61059c9085613e81565b935060006105a988612e57565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b81526004016105d99190613e3e565b602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a9190613e52565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b815260040161064a9190613e3e565b602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190613e52565b90506000670de0b6b3a76400006106a2848b613e94565b6106ac9190613ec1565b90506000670de0b6b3a76400006106c3848b613e94565b6106cd9190613ec1565b905060648211806106de5750606481115b9a50505050505050505050505b92915050565b805460038201546000916001600160a01b03169060ff600160a81b8204169083908190610740908590600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b9150915060008061075386858588612b8a565b909250905060006107648284613e81565b116040518060400160405280601081526020016f54532d3234207a65726f2076616c756560801b815250906107b55760405162461bcd60e51b81526004016107ac9190613e07565b60405180910390fd5b506107c08183613e81565b6107d282670de0b6b3a7640000613e94565b6107dc9190613ec1565b98975050505050505050565b6001830154604080516060810190915260228082526001600160a01b039092169182151591906148186020830139906108345760405162461bcd60e51b81526004016107ac9190613e07565b506003840154600160a81b900460ff1615610880576002840154610862906001600160a01b03168284612f46565b600384015461087b906001600160a01b03168285612f46565b6108b2565b6002840154610899906001600160a01b03168285612f46565b60038401546108b2906001600160a01b03168284612f46565b60408051848152602081018490527fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89910160405180910390a150505050565b600080846001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613ed5565b84519091506000805b82811015610aa557600087828151811061097b5761097b613ef2565b60200260200101519050896001600160a01b0316816001600160a01b0316036109ca578682815181106109b0576109b0613ef2565b6020026020010151836109c39190613e81565b9250610a94565b846001600160a01b031663a9dd14d68984815181106109eb576109eb613ef2565b60200260200101518c8a8681518110610a0657610a06613ef2565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015610a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a879190613e52565b610a919084613e81565b92505b50610a9e81613f08565b905061095f565b50925050505b949350505050565b8154600383015460048401546040805180820190915260158152745533532d372057726f6e67206c697175696469747960581b60208201526060936001600160a01b031692600160c81b8104600290810b93600160e01b830490910b926001600160801b03630100000090920482169260ff600160a81b90910416918816831015610b515760405162461bcd60e51b81526004016107ac9190613e07565b5060408051600280825260608201835290916020830190803683370190505060405163a34123a760e01b8152600286810b600483015285900b60248201526001600160801b03891660448201529096506001600160a01b0386169063a34123a79060640160408051808303816000875af1158015610bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf79190613e1a565b87600081518110610c0a57610c0a613ef2565b6020026020010188600181518110610c2457610c24613ef2565b6020908102919091010191909152526040516309e3d67b60e31b81526001600160a01b03861690634f1eb3d890610c6e903090889088906001600160801b03908190600401613f21565b60408051808303816000875af1158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190613f5e565b50610cbd90508783613f8d565b8860040160036101000a8154816001600160801b0302191690836001600160801b031602179055508015610d5e5785600181518110610cfe57610cfe613ef2565b602002602001015186600081518110610d1957610d19613ef2565b602002602001015187600081518110610d3457610d34613ef2565b6020026020010188600181518110610d4e57610d4e613ef2565b6020908102919091010191909152525b505050505092915050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190613fad565b62ffffff166064149050919050565b815460028301546040805163313ce56760e01b815290516000936001600160a01b0390811693859373__$79fe6ec7a3db45dafbed12dca1c6dad764$__9363556ce728939092169163313ce567916004808201926020929091908290030181865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190613fe8565b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865af4158015610eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed59190613e52565b6003860154604051635620c32d60e11b81526001600160a01b0380861660048301529091166024820152909150600090829073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190613e52565b610f719190613e94565b905073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__6351265e89878773__$105aa07724e80e292e8a4b4cc62d6ec972$__6317b13c95886040518263ffffffff1660e01b8152600401610fc69190613e3e565b602060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614003565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015260020b604482015260648101849052608401606060405180830381865af4158015611062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110869190614020565b5090979650505050505050565b604080516002808252606082810190935260009182918160200160208202803683370190505092506000866001815181106110d0576110d0613ef2565b6020026020010151111561137b57831561115757856001815181106110f7576110f7613ef2565b60200260200101518660008151811061111257611112613ef2565b60200260200101518760008151811061112d5761112d613ef2565b602002602001018860018151811061114757611147613ef2565b6020908102919091010191909152525b600073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__6317c22c3c8b8b8b8b60008151811061118957611189613ef2565b60200260200101518c6001815181106111a4576111a4613ef2565b60200260200101516040518663ffffffff1660e01b81526004016111cc959493929190614071565b606060405180830381865af41580156111e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120d91906140a5565b8660008151811061122057611220613ef2565b602002602001018760018151811061123a5761123a613ef2565b6020908102919091010192909252919052604051633c8a7d8d60e01b815230600482015260028b810b60248301528a900b60448201526001600160801b038216606482015260a06084820152600060a48201529091506001600160a01b038b1690633c8a7d8d9060c40160408051808303816000875af11580156112c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e69190613e1a565b50506001600160801b03811692506112fe81876140d3565b91508415611379578360018151811061131957611319613ef2565b60200260200101518460008151811061133457611334613ef2565b60200260200101518560008151811061134f5761134f613ef2565b602002602001018660018151811061136957611369613ef2565b6020908102919091010191909152525b505b96509650969350505050565b60408051600280825260608083018452926020830190803683375050835460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa1580156113f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114169190614105565b505050506003860154600480880154604051630544f36560e31b815295965073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__95632a279b28955061148894508793600160c81b8104600290810b94600160e01b909204900b92630100000090046001600160801b03169101614194565b6040805180830381865af41580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190613e1a565b836000815181106114db576114db613ef2565b60200260200101846001815181106114f5576114f5613ef2565b6020908102919091010191909152526003830154600160a81b900460ff161561158b578160018151811061152b5761152b613ef2565b60200260200101518260008151811061154657611546613ef2565b60200260200101518360008151811061156157611561613ef2565b602002602001018460018151811061157b5761157b613ef2565b6020908102919091010191909152525b50919050565b60408051808201825260028401546001600160a01b0390811682526003850154166020820152905163bd13c52960e01b81526000916060918883013591908390859073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063bd13c52990611607908f908f908f908f908a908f906004016141d0565b600060405180830381865af4158015611624573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164c91908101906142e2565b9197509250905080156116ef5773__$8f1afe7577f9ab973017c74eca19b86f3c$__6326eadaa38e8e600460200201602081019061168a91906139fc565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044810184905260640160006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505b6040805182815260208d8101359082015260008183015290517f3715d08a7dcc9d792a5a426f62429b9f889a7b140004f9f85190a48485695cf19181900360600190a1600184148061174957506002841480156117495750855b156117c85787546003890154611789916001600160a01b031690600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b60038a01805465ffffffffffff60c81b1916600160e01b62ffffff9384160262ffffff60c81b191617600160c81b939092169290920217905590935083905b5050505097509795505050505050565b60408051600280825260608083018452926020830190803683375050845460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa158015611843573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118679190614105565b5050506003880154604051630544f36560e31b815294955073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__94632a279b2894506118c59350869250600160c81b8204600290810b92600160e01b9004900b908990600401614194565b6040805180830381865af41580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190613e1a565b8360008151811061191857611918613ef2565b602002602001018460018151811061193257611932613ef2565b6020908102919091010191909152526003840154600160a81b900460ff16156119c8578160018151811061196857611968613ef2565b60200260200101518260008151811061198357611983613ef2565b60200260200101518360008151811061199e5761199e613ef2565b60200260200101846001815181106119b8576119b8613ef2565b6020908102919091010191909152525b5092915050565b60408051808201909152601181527054532d31207a65726f206164647265737360781b60208201526001600160a01b038616611a1e5760405162461bcd60e51b81526004016107ac9190613e07565b506000856001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190613ed5565b90506000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190613ed5565b9050611af36135dc565b600073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__63ea8668158a6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190613fad565b6040516001600160e01b031960e084901b16815262ffffff9091166004820152602401602060405180830381865af4158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd59190614003565b90508760020b600014611caa5780611bed818a61433b565b611bf79190614375565b60020b8860020b146040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525090611c535760405162461bcd60e51b81526004016107ac9190613e07565b5080611c5f818961433b565b611c699190614375565b60020b8760020b1460405180606001604052806022815260200161483a6022913990611ca85760405162461bcd60e51b81526004016107ac9190613e07565b505b600281810b80845260405163362ad1e560e11b81526001600160a01b038c166004820152918a900b6024830152604482015273__$105aa07724e80e292e8a4b4cc62d6ec972$__90636c55a3ca906064016040805180830381865af4158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614395565b600290810b60408086019190915291810b6020808601919091529089900b60608086019190915282516080810184526001600160a01b038d811682528a811693820193909352878316938101939093529085169082015273__$b1ba452cecccdd06eb05ace2d0a762c7e1$__915063b8b4a449908c9084611dbb8d610d69565b896040518663ffffffff1660e01b8152600401611ddc9594939291906143c4565b60006040518083038186803b158015611df457600080fd5b505af4158015611e08573d6000803e3d6000fd5b505050506000896001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e709190613ed5565b60405163095ea7b360e01b81526001600160a01b03808316600483015260001960248301529192509085169063095ea7b3906044016020604051808303816000875af1158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190614441565b5060405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015284169063095ea7b3906044016020604051808303816000875af1158015611f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5d9190614441565b505050505050505050505050565b6001810154815460038301546040805160028082526060808301845295869586956001600160a01b03928316959290911693600160c81b8204840b93600160e01b909204820b92909190602083019080368337505050600289015481519198506001600160a01b0316908890600090611fe657611fe6613ef2565b6001600160a01b039283166020918202929092010152600389015488519116908890600190811061201957612019613ef2565b6001600160a01b039290921660209283029190910182015260408051600280825260608201835290929091908301908036833701905050945060005b87518110156121135787818151811061207057612070613ef2565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120a39190613e3e565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e49190613e52565b8682815181106120f6576120f6613ef2565b60209081029190910101528061210b81613f08565b915050612055565b506040805160028082526060820183529091602083019080368337019050506004890154909650630100000090046001600160801b03161561229f5760405163a34123a760e01b8152600283810b600483015282900b6024820152600060448201526001600160a01b0384169063a34123a79060640160408051808303816000875af11580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613e1a565b50506040516309e3d67b60e31b81526001600160a01b03841690634f1eb3d890612208903090869086906001600160801b03908190600401613f21565b60408051808303816000875af1158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a9190613f5e565b816001600160801b03169150806001600160801b031690508760008151811061227557612275613ef2565b602002602001018860018151811061228f5761228f613ef2565b6020908102919091010191909152525b7fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89866000815181106122d3576122d3613ef2565b6020026020010151876001815181106122ee576122ee613ef2565b602002602001015160405161230d929190918252602082015260400190565b60405180910390a16003880154600160a81b900460ff161561239c578560018151811061233c5761233c613ef2565b60200260200101518660008151811061235757612357613ef2565b60200260200101518760008151811061237257612372613ef2565b602002602001018860018151811061238c5761238c613ef2565b6020908102919091010191909152525b60005b875181101561250c5760008882815181106123bc576123bc613ef2565b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016123ef9190613e3e565b602060405180830381865afa15801561240c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124309190613e52565b905080156124fb5788828151811061244a5761244a613ef2565b60209081029190910101516040516323b872dd60e01b81526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf9190614441565b50808883815181106124e3576124e3613ef2565b602002602001018181516124f79190613e81565b9052505b5061250581613f08565b905061239f565b50505050509193909250565b60606125226135fa565b61253a8161253360208b018b6139fc565b8b86612f9d565b61014081015160408083015160038c01549151635620c32d60e11b81526001600160a01b0391821660048201529116602482015273__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af41580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190613e52565b6125d89190613e94565b61012082015260408082015190516317b13c9560e01b8152600091829173__$105aa07724e80e292e8a4b4cc62d6ec972$__916317b13c959161261e9190600401613e3e565b602060405180830381865af415801561263b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265f9190614003565b60208401516101208501516040516351265e8960e01b8152600481018f90526001600160a01b039092166024830152600283900b6044830152606482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__906351265e8990608401606060405180830381865af41580156126dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127009190614020565b8560e001866101000182600381111561271b5761271b61445e565b600381111561272c5761272c61445e565b905291151590915250915081156127b25773__$b1ba452cecccdd06eb05ace2d0a762c7e1$__634aa009158c8560e001518661010001516040518463ffffffff1660e01b815260040161278193929190614474565b60006040518083038186803b15801561279957600080fd5b505af41580156127ad573d6000803e3d6000fd5b505050505b8515806127bc5750815b6040518060400160405280601981526020017f5533532d39204e6f20726562616c616e6365206e656564656400000000000000815250906128105760405162461bcd60e51b81526004016107ac9190613e07565b5081156129ea5773__$105aa07724e80e292e8a4b4cc62d6ec972$__63e4ee4bf78b8d8b8d8c8960c00151886040518863ffffffff1660e01b815260040161285e97969594939291906144d8565b60006040518083038186803b15801561287657600080fd5b505af415801561288a573d6000803e3d6000fd5b50505050600073__$8f1afe7577f9ab973017c74eca19b86f3c$__63ac2a37d685602001518c876060015188608001518960c001516040518663ffffffff1660e01b81526004016128df95949392919061455e565b600060405180830381865af41580156128fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129249190810190614592565b9550905080156129a8576040516326eadaa360e01b8152600481018e90526001600160a01b03891660248201526044810182905273__$8f1afe7577f9ab973017c74eca19b86f3c$__906326eadaa39060640160006040518083038186803b15801561298f57600080fd5b505af41580156129a3573d6000803e3d6000fd5b505050505b60408051828152602081018b905260008183015290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a1505b50505098975050505050505050565b6002810154604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015612a45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a6d91908101906145d8565b8260030160009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ac2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aea91908101906145d8565b83546040805163ddca3f4360e01b81529051612b62926001600160a01b03169163ddca3f439160048083019260209291908290030181865afa158015612b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b589190613fad565b62ffffff16613194565b604051602001612b749392919061464e565b6040516020818303038152906040529050919050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf19190613ed5565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613e52565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190613fe8565b60ff169050816000612cf483600a6147a3565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015290915081612d3c5760405162461bcd60e51b81526004016107ac9190613e07565b5060008073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__6317c22c3c8e8e8e88886040518663ffffffff1660e01b8152600401612d7f959493929190614071565b606060405180830381865af4158015612d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc091906140a5565b509150915089612e0957612ddc82670de0b6b3a7640000613e94565b8387612df084670de0b6b3a7640000613e94565b612dfa9190613e94565b612e049190613ec1565b612e43565b8286612e1d83670de0b6b3a7640000613e94565b612e279190613e94565b612e319190613ec1565b612e4383670de0b6b3a7640000613e94565b985098505050505050505094509492505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebb9190613ed5565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106eb9190613ed5565b6000806000612f2a87613294565b9050612f3881878787613305565b925092505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612f989084906133cf565b505050565b81546001600160a01b0316604080860191909152805160608101909152600583018054829060ff166003811115612fd657612fd661445e565b6003811115612fe757612fe761445e565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161300757505050918352505060408051608081019182905260209092019190600584019060049082845b815481526020019060010190808311613040575050509190925250505084526001600160a01b03838116602080870191909152600284015482166060870181905260038501549283166080880152600160a01b90920460ff16151560a0870152600091825282905260409020546130b6906134a1565b60c08501515260808401516001600160a01b03166000908152602082905260409020546130e2906134a1565b60c08501516001602002018181525050600084606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315a9190613fe8565b60ff1690506012811061316e576001613184565b6131798160126147af565b61318490600a6147a3565b6101409095019490945250505050565b6060816000036131bb5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156131e557806131cf81613f08565b91506131de9050600a83613ec1565b91506131bf565b6000816001600160401b038111156131ff576131ff6137b1565b6040519080825280601f01601f191660200182016040528015613229576020820181803683370190505b5090505b8415610aab5761323e6001836147af565b915061324b600a866147c2565b613256906030613e81565b60f81b81838151811061326b5761326b613ef2565b60200101906001600160f81b031916908160001a90535061328d600a86613ec1565b945061322d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f89190614105565b5093979650505050505050565b6000808061331386866147d6565b905060008460020b8260020b146133345761332f60028361433b565b613337565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063cd8e20e7906064016040805180830381865af415801561339c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c09190614395565b93509350505094509492505050565b6000613424826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134b99092919063ffffffff16565b805190915015612f9857808060200190518101906134429190614441565b612f985760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ac565b600081156134af57816106eb565b620186a092915050565b6060610aab848460008585600080866001600160a01b031685876040516134e091906147fb565b60006040518083038185875af1925050503d806000811461351d576040519150601f19603f3d011682016040523d82523d6000602084013e613522565b606091505b50915091506135338783838761353e565b979650505050505050565b606083156135ad5782516000036135a6576001600160a01b0385163b6135a65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107ac565b5081610aab565b610aab83838151156135c25781518083602001fd5b8060405162461bcd60e51b81526004016107ac9190613e07565b60405180608001604052806004906020820280368337509192915050565b60405180610160016040528061360e613660565b815260006020820181905260408201819052606082018190526080820181905260a082015260c00161363e61368d565b8152600060208201819052604082018190526060820181905260809091015290565b6040805160608101909152806000815260200161367b6135dc565b81526020016136886135dc565b905290565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146136c057600080fd5b50565b8060020b81146136c057600080fd5b80151581146136c057600080fd5b600080600080608085870312156136f657600080fd5b8435613701816136ab565b93506020850135613711816136c3565b92506040850135613721816136c3565b91506060850135613731816136d2565b939692955090935050565b60006020828403121561374e57600080fd5b5035919050565b6000806040838503121561376857600080fd5b82359150602083013561377a816136ab565b809150509250929050565b60008060006060848603121561379a57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137ef576137ef6137b1565b604052919050565b60006001600160401b03821115613810576138106137b1565b5060051b60200190565b600082601f83011261382b57600080fd5b8135602061384061383b836137f7565b6137c7565b82815260059290921b8401810191818101908684111561385f57600080fd5b8286015b8481101561387a5780358352918301918301613863565b509695505050505050565b6000806000806080858703121561389b57600080fd5b84356138a6816136ab565b93506020858101356138b7816136ab565b935060408601356001600160401b03808211156138d357600080fd5b818801915088601f8301126138e757600080fd5b81356138f561383b826137f7565b81815260059190911b8301840190848101908b83111561391457600080fd5b938501935b8285101561393b57843561392c816136ab565b82529385019390850190613919565b96505050606088013592508083111561395357600080fd5b50506139618782880161381a565b91505092959194509250565b6001600160801b03811681146136c057600080fd5b6000806040838503121561399557600080fd5b82359150602083013561377a8161396d565b600081518084526020808501945080840160005b838110156139d7578151875295820195908201906001016139bb565b509495945050505050565b6020815260006139f560208301846139a7565b9392505050565b600060208284031215613a0e57600080fd5b81356139f5816136ab565b60008060008060008060c08789031215613a3257600080fd5b8635613a3d816136ab565b95506020870135613a4d816136c3565b94506040870135613a5d816136c3565b935060608701356001600160401b03811115613a7857600080fd5b613a8489828a0161381a565b9350506080870135613a958161396d565b915060a0870135613aa5816136d2565b809150509295509295509295565b606081526000613ac660608301866139a7565b90508360208301526001600160801b0383166040830152949350505050565b80608081018310156106eb57600080fd5b60006001600160401b03821115613b0f57613b0f6137b1565b50601f01601f191660200190565b600082601f830112613b2e57600080fd5b8135613b3c61383b82613af6565b818152846020838601011115613b5157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060006101c0888a031215613b8a57600080fd5b8735965060c0880189811115613b9f57600080fd5b602089019650613baf8a82613ae5565b9550506101408801356001600160401b0380821115613bcd57600080fd5b613bd98b838c01613b1d565b95506101608a0135915080821115613bf057600080fd5b50613bfd8a828b01613b1d565b93505061018088013591506101a0880135905092959891949750929550565b8215158152604060208201526000610aab60408301846139a7565b6000806000806000806000610140888a031215613c5357600080fd5b873596506020880135613c65816136ab565b95506040880135613c75816136ab565b94506060880135613c85816136c3565b93506080880135613c95816136c3565b925060a0880135613ca5816136ab565b9150613cb48960c08a01613ae5565b905092959891949750929550565b606080825284519082018190526000906020906080840190828801845b82811015613d045781516001600160a01b031684529284019290840190600101613cdf565b50505083810382850152613d1881876139a7565b9150508281036040840152613d2d81856139a7565b9695505050505050565b600080600080600080600080610120898b031215613d5457600080fd5b8835975060208901359650608089018a811115613d7057600080fd5b60408a01965035945060a0890135935060c0890135613d8e816136ab565b925060e0890135613d9e816136d2565b8092505061010089013590509295985092959890939650565b60005b83811015613dd2578181015183820152602001613dba565b50506000910152565b60008151808452613df3816020860160208601613db7565b601f01601f19169290920160200192915050565b6020815260006139f56020830184613ddb565b60008060408385031215613e2d57600080fd5b505080516020909101519092909150565b6001600160a01b0391909116815260200190565b600060208284031215613e6457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106eb576106eb613e6b565b80820281158282048414176106eb576106eb613e6b565b634e487b7160e01b600052601260045260246000fd5b600082613ed057613ed0613eab565b500490565b600060208284031215613ee757600080fd5b81516139f5816136ab565b634e487b7160e01b600052603260045260246000fd5b600060018201613f1a57613f1a613e6b565b5060010190565b6001600160a01b03959095168552600293840b60208601529190920b60408401526001600160801b03918216606084015216608082015260a00190565b60008060408385031215613f7157600080fd5b8251613f7c8161396d565b602084015190925061377a8161396d565b6001600160801b038281168282160390808211156119c8576119c8613e6b565b600060208284031215613fbf57600080fd5b815162ffffff811681146139f557600080fd5b805160ff81168114613fe357600080fd5b919050565b600060208284031215613ffa57600080fd5b6139f582613fd2565b60006020828403121561401557600080fd5b81516139f5816136c3565b60008060006060848603121561403557600080fd5b8351614040816136d2565b6020850151909350614051816136d2565b60408501519092506004811061406657600080fd5b809150509250925092565b6001600160a01b03959095168552600293840b60208601529190920b60408401526060830191909152608082015260a00190565b6000806000606084860312156140ba57600080fd5b835192506020840151915060408401516140668161396d565b6001600160801b038181168382160190808211156119c8576119c8613e6b565b805161ffff81168114613fe357600080fd5b600080600080600080600060e0888a03121561412057600080fd5b875161412b816136ab565b602089015190975061413c816136c3565b955061414a604089016140f3565b9450614158606089016140f3565b9350614166608089016140f3565b925061417460a08901613fd2565b915060c0880151614184816136d2565b8091505092959891949750929550565b6001600160a01b03949094168452600292830b6020850152910b60408301526001600160801b0316606082015260800190565b60808183375050565b60006101c08289835b600581101561420b5781356141ed816136ab565b6001600160a01b0316835260209283019291909101906001016141d9565b50505060808860a08501378061012084015261422981840188613ddb565b905082810361014084015261423e8187613ddb565b91505061016082018460005b60028110156142725781516001600160a01b031683526020928301929091019060010161424a565b505050826101a0830152979650505050505050565b600082601f83011261429857600080fd5b815160206142a861383b836137f7565b82815260059290921b840181019181810190868411156142c757600080fd5b8286015b8481101561387a57805183529183019183016142cb565b6000806000606084860312156142f757600080fd5b8351614302816136d2565b60208501519093506001600160401b0381111561431e57600080fd5b61432a86828701614287565b925050604084015190509250925092565b60008160020b8360020b8061435257614352613eab565b627fffff1982146000198214161561436c5761436c613e6b565b90059392505050565b60008260020b8260020b028060020b91508082146119c8576119c8613e6b565b600080604083850312156143a857600080fd5b82516143b3816136c3565b602084015190925061377a816136c3565b8581526101c0810160208083018760005b60048110156143fb5781516001600160a01b0316835291830191908301906001016143d5565b50505060a083018660005b600481101561442657815160020b83529183019190830190600101614406565b50505050831515610120830152613d2d6101408301846141c7565b60006020828403121561445357600080fd5b81516139f5816136d2565b634e487b7160e01b600052602160045260246000fd5b838152821515602082015260608101600483106144a157634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b8060005b60028110156144d25781518452602093840193909101906001016144b3565b50505050565b6101208101818960005b60028110156145145781356144f6816136ab565b6001600160a01b0316835260209283019291909101906001016144e2565b5050506040820188905260608201879052608082018690526001600160a01b03851660a083015261454860c08301856144af565b8260020b61010083015298975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c08101613d2d60808301846144af565b600080604083850312156145a557600080fd5b8251915060208301516001600160401b038111156145c257600080fd5b6145ce85828601614287565b9150509250929050565b6000602082840312156145ea57600080fd5b81516001600160401b0381111561460057600080fd5b8201601f8101841361461157600080fd5b805161461f61383b82613af6565b81815285602083850101111561463457600080fd5b614645826020830160208601613db7565b95945050505050565b6502ab734ab19960d51b81526000845161466f816006850160208901613db7565b602f60f81b6006918401918201528451614690816007840160208901613db7565b602d60f81b6007929091019182015283516146b2816008840160208801613db7565b0160080195945050505050565b600181815b808511156146fa5781600019048211156146e0576146e0613e6b565b808516156146ed57918102915b93841c93908002906146c4565b509250929050565b600082614711575060016106eb565b8161471e575060006106eb565b8160018114614734576002811461473e5761475a565b60019150506106eb565b60ff84111561474f5761474f613e6b565b50506001821b6106eb565b5060208310610133831016604e8410600b841016171561477d575081810a6106eb565b61478783836146bf565b806000190482111561479b5761479b613e6b565b029392505050565b60006139f58383614702565b818103818111156106eb576106eb613e6b565b6000826147d1576147d1613eab565b500690565b600282810b9082900b03627fffff198112627fffff821317156106eb576106eb613e6b565b6000825161480d818460208701613db7565b919091019291505056fe5533532d3133205a65726f2073747261746567792070726f66697420686f6c6465725042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a26469706673582212200343d57e33cce12f7e7959de066953f2dc0fe1356e55d91afd9e2cbb9643e27a64736f6c63430008110033", + "numDeployments": 34, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"loss\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"profitToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"coveredByRewards\",\"type\":\"uint256\"}],\"name\":\"Rebalanced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"loss\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"profitToCover\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"coveredByRewards\",\"type\":\"uint256\"}],\"name\":\"RebalancedDebt\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee1\",\"type\":\"uint256\"}],\"name\":\"UniV3FeesClaimed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"controller\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"rewardTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"calcEarned\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"},{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"},{\"internalType\":\"bool\",\"name\":\"depositorSwapTokens\",\"type\":\"bool\"}],\"name\":\"getEntryDataProportions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"}],\"name\":\"isStablePool\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"claimRewards(PairBasedStrategyLogicLib.PairState storage)\":{\"returns\":{\"amountsOut\":\"An array containing the amounts of token0 and token1 claimed as rewards.\",\"tokensOut\":\"An array containing tokenA and tokenB.\"}},\"enter(IUniswapV3Pool,int24,int24,uint256[],uint128,bool)\":{\"params\":{\"_depositorSwapTokens\":\"A boolean indicating if need to use token B instead of token A.\",\"amountsDesired_\":\"An array containing the desired amounts of tokens to provide liquidity.\",\"lowerTick\":\"The lower tick value for the pool.\",\"pool\":\"The Uniswap V3 pool to provide liquidity to.\",\"totalLiquidity\":\"The current total liquidity in the pool.\",\"upperTick\":\"The upper tick value for the pool.\"},\"returns\":{\"amountsConsumed\":\"An array containing the consumed amounts for each token in the pool.\",\"liquidityOut\":\"The amount of liquidity added to the pool.\",\"totalLiquidityNew\":\"The updated total liquidity after providing liquidity.\"}},\"exit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"params\":{\"liquidityAmountToExit\":\"The amount of liquidity to exit.\",\"pairState\":\"The State storage object.\"},\"returns\":{\"amountsOut\":\"An array containing the collected amounts for each token in the pool.\"}},\"getEntryDataProportions(IUniswapV3Pool,int24,int24,bool)\":{\"params\":{\"depositorSwapTokens\":\"A boolean indicating if need to use token B instead of token A.\",\"lowerTick\":\"The lower tick of the pool's main range.\",\"pool\":\"Pool instance.\",\"upperTick\":\"The upper tick of the pool's main range.\"},\"returns\":{\"_0\":\"prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\",\"_1\":\"prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\"}},\"getFees(PairBasedStrategyLogicLib.PairState storage)\":{\"params\":{\"pairState\":\"The State storage containing the pool's information.\"},\"returns\":{\"fee0\":\"The fees generated for the first token in the pool.\",\"fee1\":\"The fees generated for the second token in the pool.\"}},\"getPoolReserves(PairBasedStrategyLogicLib.PairState storage)\":{\"params\":{\"pairState\":\"The State storage containing the pool's information.\"},\"returns\":{\"reserves\":\"An array containing the reserve amounts of the contract owned liquidity.\"}},\"initStrategyState(UniswapV3ConverterStrategyLogicLib.State storage,address,address,int24,int24,address,uint256[4])\":{\"params\":{\"fuseThresholds\":\"Fuse thresholds for tokens (stable pool only)\"}},\"isStablePool(IUniswapV3Pool)\":{\"params\":{\"pool\":\"The Uniswap V3 pool.\"},\"returns\":{\"_0\":\"A boolean indicating if the pool is stable.\"}},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter)\":{\"returns\":{\"needRebalance\":\"A boolean indicating if {rebalanceNoSwaps} should be called\"}},\"quoteExit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"params\":{\"liquidityAmountToExit\":\"The amount of liquidity to exit.\"},\"returns\":{\"amountsOut\":\"An array containing the estimated exit amounts for each token in the pool.\"}},\"rebalanceNoSwaps(IConverterStrategyBase.ConverterStrategyBaseState storage,PairBasedStrategyLogicLib.PairState storage,address[2],uint256,uint256,address,bool,mapping(address => uint256) storage)\":{\"params\":{\"checkNeedRebalance_\":\"True if the function should ensure that the rebalance is required\",\"converterLiquidator\":\"[TetuConverter, TetuLiquidator]\",\"totalAssets_\":\"Current value of totalAssets()\"},\"returns\":{\"tokenAmounts\":\"Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\"}},\"withdrawByAggStep(IConverterStrategyBase.ConverterStrategyBaseState storage,address[5],uint256[4],bytes,bytes,PairBasedStrategyLogicLib.PairState storage,mapping(address => uint256) storage)\":{\"params\":{\"addr_\":\"[tokenToSwap, aggregator, controller, converter, splitter]\",\"values_\":\"[amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\"},\"returns\":{\"completed\":\"All debts were closed, leftovers were swapped to proper proportions\",\"tokenAmountsOut\":\"Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"claimRewards(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Claim rewards from the Uniswap V3 pool.\"},\"enter(IUniswapV3Pool,int24,int24,uint256[],uint128,bool)\":{\"notice\":\"Enter the pool and provide liquidity with desired token amounts.\"},\"exit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"notice\":\"Exit the pool and collect tokens proportional to the liquidity amount to exit.\"},\"getEntryDataProportions(IUniswapV3Pool,int24,int24,bool)\":{\"notice\":\"Calculate proportions of the tokens for entry kind 1\"},\"getFees(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\"},\"getPoolReserves(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Retrieve the reserves of a Uniswap V3 pool managed by this contract.\"},\"getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage)\":{\"notice\":\"Get proportion of not-underlying in the pool, [0...1e18] prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\"},\"isStablePool(IUniswapV3Pool)\":{\"notice\":\"Check if the given pool is a stable pool.\"},\"needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage,ITetuConverter)\":{\"notice\":\"Determine if the strategy needs to be rebalanced.\"},\"quoteExit(PairBasedStrategyLogicLib.PairState storage,uint128)\":{\"notice\":\"Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\"},\"rebalanceNoSwaps(IConverterStrategyBase.ConverterStrategyBaseState storage,PairBasedStrategyLogicLib.PairState storage,address[2],uint256,uint256,address,bool,mapping(address => uint256) storage)\":{\"notice\":\"Make rebalance without swaps (using borrowing only).\"},\"withdrawByAggStep(IConverterStrategyBase.ConverterStrategyBaseState storage,address[5],uint256[4],bytes,bytes,PairBasedStrategyLogicLib.PairState storage,mapping(address => uint256) storage)\":{\"notice\":\"Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":\"UniswapV3ConverterStrategyLogicLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\n\\nlibrary StringLib {\\n\\n /// @dev Inspired by OraclizeAPI's implementation - MIT license\\n /// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\\n function toString(uint value) external pure returns (string memory) {\\n return _toString(value);\\n }\\n\\n function _toString(uint value) internal pure returns (string memory) {\\n if (value == 0) {\\n return \\\"0\\\";\\n }\\n uint temp = value;\\n uint digits;\\n while (temp != 0) {\\n digits++;\\n temp /= 10;\\n }\\n bytes memory buffer = new bytes(digits);\\n while (value != 0) {\\n digits -= 1;\\n buffer[digits] = bytes1(uint8(48 + uint(value % 10)));\\n value /= 10;\\n }\\n return string(buffer);\\n }\\n\\n function toAsciiString(address x) external pure returns (string memory) {\\n return _toAsciiString(x);\\n }\\n\\n function _toAsciiString(address x) internal pure returns (string memory) {\\n bytes memory s = new bytes(40);\\n for (uint i = 0; i < 20; i++) {\\n bytes1 b = bytes1(uint8(uint(uint160(x)) / (2 ** (8 * (19 - i)))));\\n bytes1 hi = bytes1(uint8(b) / 16);\\n bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));\\n s[2 * i] = _char(hi);\\n s[2 * i + 1] = _char(lo);\\n }\\n return string(s);\\n }\\n\\n function char(bytes1 b) external pure returns (bytes1 c) {\\n return _char(b);\\n }\\n\\n function _char(bytes1 b) internal pure returns (bytes1 c) {\\n if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);\\n else return bytes1(uint8(b) + 0x57);\\n }\\n\\n}\\n\",\"keccak256\":\"0xe7fef8dd3d994fd08ac32e3eff07f39546cc58dc0101f5fc7c0efebfb4f3f01a\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3ConverterStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./UniswapV3DebtLib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/AppLib.sol\\\";\\r\\nimport \\\"../../libs/AppErrors.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/lib/StringLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3ConverterStrategyLogicLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_STABLE = 300;\\r\\n uint internal constant LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE = 500;\\r\\n uint internal constant HARD_WORK_USD_FEE_THRESHOLD = 100;\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event Rebalanced(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event RebalancedDebt(uint loss, uint profitToCover, uint coveredByRewards);\\r\\n event UniV3FeesClaimed(uint fee0, uint fee1);\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n\\r\\n struct State {\\r\\n PairBasedStrategyLogicLib.PairState pair;\\r\\n // additional (specific) state\\r\\n\\r\\n /// @dev reserve space for future needs\\r\\n uint[10] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceLocal {\\r\\n /// @notice Fuse for token A and token B\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n ITetuConverter converter;\\r\\n IUniswapV3Pool pool;\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool isStablePool;\\r\\n uint[2] liquidationThresholdsAB;\\r\\n\\r\\n bool fuseStatusChangedAB;\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB;\\r\\n\\r\\n uint poolPrice;\\r\\n uint poolPriceAdjustment;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Helpers\\r\\n\\r\\n /// @dev Gets the liquidator swap slippage based on the pool type (stable or volatile).\\r\\n /// @param pool The IUniswapV3Pool instance.\\r\\n /// @return The liquidator swap slippage percentage.\\r\\n function _getLiquidatorSwapSlippage(IUniswapV3Pool pool) internal view returns (uint) {\\r\\n return isStablePool(pool) ? LIQUIDATOR_SWAP_SLIPPAGE_STABLE : LIQUIDATOR_SWAP_SLIPPAGE_VOLATILE;\\r\\n }\\r\\n\\r\\n /// @notice Check if the given pool is a stable pool.\\r\\n /// @param pool The Uniswap V3 pool.\\r\\n /// @return A boolean indicating if the pool is stable.\\r\\n function isStablePool(IUniswapV3Pool pool) public view returns (bool) {\\r\\n return pool.fee() == 100;\\r\\n }\\r\\n\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function initStrategyState(\\r\\n State storage state,\\r\\n address controller_,\\r\\n address pool,\\r\\n int24 tickRange,\\r\\n int24 rebalanceTickRange,\\r\\n address asset_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n require(pool != address(0), AppErrors.ZERO_ADDRESS);\\r\\n address token0 = IUniswapV3Pool(pool).token0();\\r\\n address token1 = IUniswapV3Pool(pool).token1();\\r\\n\\r\\n int24[4] memory tickData;\\r\\n {\\r\\n int24 tickSpacing = UniswapV3Lib.getTickSpacing(IUniswapV3Pool(pool).fee());\\r\\n if (tickRange != 0) {\\r\\n require(tickRange == tickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_TICK_RANGE);\\r\\n require(rebalanceTickRange == rebalanceTickRange / tickSpacing * tickSpacing, PairBasedStrategyLib.INCORRECT_REBALANCE_TICK_RANGE);\\r\\n }\\r\\n tickData[0] = tickSpacing;\\r\\n (tickData[1], tickData[2]) = UniswapV3DebtLib.calcTickRange(pool, tickRange, tickSpacing);\\r\\n tickData[3] = rebalanceTickRange;\\r\\n }\\r\\n\\r\\n PairBasedStrategyLogicLib.setInitialDepositorValues(\\r\\n state.pair,\\r\\n [pool, asset_, token0, token1],\\r\\n tickData,\\r\\n isStablePool(IUniswapV3Pool(pool)),\\r\\n fuseThresholds\\r\\n );\\r\\n\\r\\n address liquidator = IController(controller_).liquidator();\\r\\n IERC20(token0).approve(liquidator, type(uint).max);\\r\\n IERC20(token1).approve(liquidator, type(uint).max);\\r\\n }\\r\\n\\r\\n function createSpecificName(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (string memory) {\\r\\n return string(abi.encodePacked(\\r\\n \\\"UniV3 \\\",\\r\\n IERC20Metadata(pairState.tokenA).symbol(),\\r\\n \\\"/\\\",\\r\\n IERC20Metadata(pairState.tokenB).symbol(),\\r\\n \\\"-\\\",\\r\\n StringLib._toString(IUniswapV3Pool(pairState.pool).fee()))\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance.\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(IUniswapV3Pool pool, int24 lowerTick, int24 upperTick, bool depositorSwapTokens) external view returns (uint, uint) {\\r\\n return UniswapV3DebtLib.getEntryDataProportions(pool, lowerTick, upperTick, depositorSwapTokens);\\r\\n }\\r\\n //endregion ------------------------------------------------ Helpers\\r\\n\\r\\n //region ------------------------------------------------ Pool info\\r\\n /// @notice Retrieve the reserves of a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return reserves An array containing the reserve amounts of the contract owned liquidity.\\r\\n function getPoolReserves(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n uint[] memory reserves\\r\\n ) {\\r\\n reserves = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (reserves[0], reserves[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.totalLiquidity\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (reserves[0], reserves[1]) = (reserves[1], reserves[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Retrieve the fees generated by a Uniswap V3 pool managed by this contract.\\r\\n /// @param pairState The State storage containing the pool's information.\\r\\n /// @return fee0 The fees generated for the first token in the pool.\\r\\n /// @return fee1 The fees generated for the second token in the pool.\\r\\n function getFees(PairBasedStrategyLogicLib.PairState storage pairState) public view returns (uint fee0, uint fee1) {\\r\\n UniswapV3Lib.PoolPosition memory position = UniswapV3Lib.PoolPosition(pairState.pool, pairState.lowerTick, pairState.upperTick, pairState.totalLiquidity, address(this));\\r\\n (fee0, fee1) = UniswapV3Lib.getFees(position);\\r\\n }\\r\\n\\r\\n /// @notice Estimate the exit amounts for a given liquidity amount in a Uniswap V3 pool.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the estimated exit amounts for each token in the pool.\\r\\n function quoteExit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) public view returns (uint[] memory amountsOut) {\\r\\n amountsOut = new uint[](2);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = IUniswapV3Pool(pairState.pool).slot0();\\r\\n\\r\\n (amountsOut[0], amountsOut[1]) = UniswapV3Lib.getAmountsForLiquidity(\\r\\n sqrtRatioX96,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n liquidityAmountToExit\\r\\n );\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Pool info\\r\\n\\r\\n //region ------------------------------------------------ Join the pool\\r\\n /// @notice Enter the pool and provide liquidity with desired token amounts.\\r\\n /// @param pool The Uniswap V3 pool to provide liquidity to.\\r\\n /// @param lowerTick The lower tick value for the pool.\\r\\n /// @param upperTick The upper tick value for the pool.\\r\\n /// @param amountsDesired_ An array containing the desired amounts of tokens to provide liquidity.\\r\\n /// @param totalLiquidity The current total liquidity in the pool.\\r\\n /// @param _depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return amountsConsumed An array containing the consumed amounts for each token in the pool.\\r\\n /// @return liquidityOut The amount of liquidity added to the pool.\\r\\n /// @return totalLiquidityNew The updated total liquidity after providing liquidity.\\r\\n function enter(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint[] memory amountsDesired_,\\r\\n uint128 totalLiquidity,\\r\\n bool _depositorSwapTokens\\r\\n ) external returns (uint[] memory amountsConsumed, uint liquidityOut, uint128 totalLiquidityNew) {\\r\\n amountsConsumed = new uint[](2);\\r\\n\\r\\n if (amountsDesired_[1] > 0) {\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsDesired_[0], amountsDesired_[1]) = (amountsDesired_[1], amountsDesired_[0]);\\r\\n }\\r\\n uint128 newLiquidity;\\r\\n (amountsConsumed[0], amountsConsumed[1], newLiquidity) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, amountsDesired_[0], amountsDesired_[1]);\\r\\n pool.mint(address(this), lowerTick, upperTick, newLiquidity, \\\"\\\");\\r\\n liquidityOut = uint(newLiquidity);\\r\\n totalLiquidityNew = totalLiquidity + newLiquidity;\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsConsumed[0], amountsConsumed[1]) = (amountsConsumed[1], amountsConsumed[0]);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountsConsumed, liquidityOut, totalLiquidityNew);\\r\\n }\\r\\n\\r\\n //endregion ------------------------------------------------ Join the pool\\r\\n\\r\\n //region ------------------------------------------------ Exit from the pool\\r\\n /// @notice Exit the pool and collect tokens proportional to the liquidity amount to exit.\\r\\n /// @param pairState The State storage object.\\r\\n /// @param liquidityAmountToExit The amount of liquidity to exit.\\r\\n /// @return amountsOut An array containing the collected amounts for each token in the pool.\\r\\n function exit(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint128 liquidityAmountToExit\\r\\n ) external returns (uint[] memory amountsOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n uint128 liquidity = pairState.totalLiquidity;\\r\\n bool _depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n\\r\\n require(liquidity >= liquidityAmountToExit, Uni3StrategyErrors.WRONG_LIQUIDITY);\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n (amountsOut[0], amountsOut[1]) = pool.burn(lowerTick, upperTick, liquidityAmountToExit);\\r\\n\\r\\n // all fees will be collected but not returned in amountsOut\\r\\n pool.collect(address(this), lowerTick, upperTick, type(uint128).max, type(uint128).max);\\r\\n\\r\\n pairState.totalLiquidity = liquidity - liquidityAmountToExit;\\r\\n\\r\\n if (_depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------ Exit from the pool\\r\\n\\r\\n //region ------------------------------------------------ Claims\\r\\n /// @notice Claim rewards from the Uniswap V3 pool.\\r\\n /// @return tokensOut An array containing tokenA and tokenB.\\r\\n /// @return amountsOut An array containing the amounts of token0 and token1 claimed as rewards.\\r\\n function claimRewards(PairBasedStrategyLogicLib.PairState storage pairState) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut,\\r\\n uint[] memory balancesBefore\\r\\n ) {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n int24 lowerTick = pairState.lowerTick;\\r\\n int24 upperTick = pairState.upperTick;\\r\\n tokensOut = new address[](2);\\r\\n tokensOut[0] = pairState.tokenA;\\r\\n tokensOut[1] = pairState.tokenB;\\r\\n\\r\\n balancesBefore = new uint[](2);\\r\\n for (uint i; i < tokensOut.length; i++) {\\r\\n balancesBefore[i] = IERC20(tokensOut[i]).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n amountsOut = new uint[](2);\\r\\n if (pairState.totalLiquidity > 0) {\\r\\n pool.burn(lowerTick, upperTick, 0);\\r\\n (amountsOut[0], amountsOut[1]) = pool.collect(\\r\\n address(this),\\r\\n lowerTick,\\r\\n upperTick,\\r\\n type(uint128).max,\\r\\n type(uint128).max\\r\\n );\\r\\n }\\r\\n\\r\\n emit UniV3FeesClaimed(amountsOut[0], amountsOut[1]);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (amountsOut[0], amountsOut[1]) = (amountsOut[1], amountsOut[0]);\\r\\n }\\r\\n\\r\\n for (uint i; i < tokensOut.length; ++i) {\\r\\n uint b = IERC20(tokensOut[i]).balanceOf(strategyProfitHolder);\\r\\n if (b > 0) {\\r\\n IERC20(tokensOut[i]).transferFrom(strategyProfitHolder, address(this), b);\\r\\n amountsOut[i] += b;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n function isReadyToHardWork(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter) external view returns (\\r\\n bool isReady\\r\\n ) {\\r\\n // check claimable amounts and compare with thresholds\\r\\n (uint fee0, uint fee1) = getFees(pairState);\\r\\n\\r\\n if (pairState.depositorSwapTokens) {\\r\\n (fee0, fee1) = (fee1, fee0);\\r\\n }\\r\\n\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n address h = pairState.strategyProfitHolder;\\r\\n\\r\\n fee0 += IERC20(tokenA).balanceOf(h);\\r\\n fee1 += IERC20(tokenB).balanceOf(h);\\r\\n\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n\\r\\n uint fee0USD = fee0 * priceA / 1e18;\\r\\n uint fee1USD = fee1 * priceB / 1e18;\\r\\n\\r\\n return fee0USD > HARD_WORK_USD_FEE_THRESHOLD || fee1USD > HARD_WORK_USD_FEE_THRESHOLD;\\r\\n }\\r\\n\\r\\n function sendFeeToProfitHolder(PairBasedStrategyLogicLib.PairState storage pairState, uint fee0, uint fee1) external {\\r\\n address strategyProfitHolder = pairState.strategyProfitHolder;\\r\\n require(strategyProfitHolder != address (0), Uni3StrategyErrors.ZERO_PROFIT_HOLDER);\\r\\n if (pairState.depositorSwapTokens) {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee1);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee0);\\r\\n } else {\\r\\n IERC20(pairState.tokenA).safeTransfer(strategyProfitHolder, fee0);\\r\\n IERC20(pairState.tokenB).safeTransfer(strategyProfitHolder, fee1);\\r\\n }\\r\\n emit UniV3FeesClaimed(fee0, fee1);\\r\\n }\\r\\n\\r\\n function calcEarned(address asset, address controller, address[] memory rewardTokens, uint[] memory amounts) external view returns (uint) {\\r\\n ITetuLiquidator liquidator = ITetuLiquidator(IController(controller).liquidator());\\r\\n uint len = rewardTokens.length;\\r\\n uint earned;\\r\\n for (uint i; i < len; ++i) {\\r\\n address token = rewardTokens[i];\\r\\n if (token == asset) {\\r\\n earned += amounts[i];\\r\\n } else {\\r\\n earned += liquidator.getPrice(rewardTokens[i], asset, amounts[i]);\\r\\n }\\r\\n }\\r\\n\\r\\n return earned;\\r\\n }\\r\\n //endregion ------------------------------------------------ Claims\\r\\n\\r\\n //region ------------------------------------------------ Rebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(PairBasedStrategyLogicLib.PairState storage pairState, ITetuConverter converter_) external view returns (\\r\\n bool needRebalance\\r\\n ) {\\r\\n address pool = pairState.pool;\\r\\n // poolPrice should have same decimals as a price from oracle == 18\\r\\n uint poolPriceAdjustment = PairBasedStrategyLib.getPoolPriceAdjustment(IERC20Metadata(pairState.tokenA).decimals());\\r\\n uint poolPrice = UniswapV3Lib.getPrice(pool, pairState.tokenB) * poolPriceAdjustment;\\r\\n (needRebalance, , ) = PairBasedStrategyLogicLib.needStrategyRebalance(\\r\\n pairState,\\r\\n converter_,\\r\\n UniswapV3DebtLib.getCurrentTick(IUniswapV3Pool(pool)),\\r\\n poolPrice\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Make rebalance without swaps (using borrowing only).\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param totalAssets_ Current value of totalAssets()\\r\\n /// @param checkNeedRebalance_ True if the function should ensure that the rebalance is required\\r\\n /// @return tokenAmounts Token amounts for deposit. If length == 0 - rebalance wasn't made and no deposit is required.\\r\\n function rebalanceNoSwaps(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n address[2] calldata converterLiquidator,\\r\\n uint totalAssets_,\\r\\n uint profitToCover,\\r\\n address splitter,\\r\\n bool checkNeedRebalance_,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n RebalanceLocal memory v;\\r\\n _initLocalVars(v, ITetuConverter(converterLiquidator[0]), pairState, liquidityThresholds_);\\r\\n v.poolPrice = UniswapV3Lib.getPrice(address(v.pool), pairState.tokenB) * v.poolPriceAdjustment;\\r\\n bool needRebalance;\\r\\n int24 tick = UniswapV3DebtLib.getCurrentTick(v.pool);\\r\\n (needRebalance,v.fuseStatusChangedAB, v.fuseStatusAB) = PairBasedStrategyLogicLib.needStrategyRebalance(pairState, v.converter, tick, v.poolPrice);\\r\\n\\r\\n // update fuse status if necessary\\r\\n if (needRebalance) {\\r\\n // we assume here, that needRebalance is true if any fuse has changed state, see needStrategyRebalance impl\\r\\n PairBasedStrategyLogicLib.updateFuseStatus(pairState, v.fuseStatusChangedAB, v.fuseStatusAB);\\r\\n }\\r\\n\\r\\n require(!checkNeedRebalance_ || needRebalance, Uni3StrategyErrors.NO_REBALANCE_NEEDED);\\r\\n\\r\\n // rebalancing debt, setting new tick range\\r\\n if (needRebalance) {\\r\\n UniswapV3DebtLib.rebalanceNoSwaps(converterLiquidator, pairState, profitToCover, totalAssets_, splitter, v.liquidationThresholdsAB, tick);\\r\\n\\r\\n uint loss;\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(v.converter, totalAssets_, v.tokenA, v.tokenB, v.liquidationThresholdsAB);\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(csbs, splitter, loss);\\r\\n }\\r\\n emit Rebalanced(loss, profitToCover, 0);\\r\\n }\\r\\n\\r\\n return tokenAmounts;\\r\\n }\\r\\n\\r\\n /// @notice Initialize {v} by state values\\r\\n function _initLocalVars(\\r\\n RebalanceLocal memory v,\\r\\n ITetuConverter converter_,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidityThresholds_\\r\\n ) internal view {\\r\\n v.pool = IUniswapV3Pool(pairState.pool);\\r\\n v.fuseAB = pairState.fuseAB;\\r\\n v.converter = converter_;\\r\\n v.tokenA = pairState.tokenA;\\r\\n v.tokenB = pairState.tokenB;\\r\\n v.isStablePool = pairState.isStablePool;\\r\\n v.liquidationThresholdsAB[0] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenA]);\\r\\n v.liquidationThresholdsAB[1] = AppLib._getLiquidationThreshold(liquidityThresholds_[v.tokenB]);\\r\\n uint poolPriceDecimals = IERC20Metadata(v.tokenA).decimals();\\r\\n v.poolPriceAdjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n /// @notice Get proportion of not-underlying in the pool, [0...1e18]\\r\\n /// prop.underlying : prop.not.underlying = 1e18 - PropNotUnderlying18 : propNotUnderlying18\\r\\n function getPropNotUnderlying18(PairBasedStrategyLogicLib.PairState storage pairState) view external returns (uint) {\\r\\n // get pool proportions\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pairState.pool);\\r\\n bool depositorSwapTokens = pairState.depositorSwapTokens;\\r\\n (int24 newLowerTick, int24 newUpperTick) = UniswapV3DebtLib._calcNewTickRange(pool, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint consumed0, uint consumed1) = UniswapV3DebtLib.getEntryDataProportions(pool, newLowerTick, newUpperTick, depositorSwapTokens);\\r\\n\\r\\n require(consumed0 + consumed1 > 0, AppErrors.ZERO_VALUE);\\r\\n return consumed1 * 1e18 / (consumed0 + consumed1);\\r\\n }\\r\\n //endregion ------------------------------------------------ Rebalance\\r\\n\\r\\n //region ------------------------------------------------ WithdrawByAgg\\r\\n /// @notice Calculate amounts to be deposited to pool, update pairState.lower/upperTick, fix loss / profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, entryToPool]\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmountsOut Amounts to be deposited to pool. This array is empty if no deposit allowed/required.\\r\\n function withdrawByAggStep(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint entryToPool = values_[3];\\r\\n address[2] memory tokens = [pairState.tokenA, pairState.tokenB];\\r\\n\\r\\n // Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n uint[] memory tokenAmounts;\\r\\n uint loss;\\r\\n (completed, tokenAmounts, loss) = PairBasedStrategyLogicLib.withdrawByAggStep(\\r\\n addr_,\\r\\n values_,\\r\\n swapData,\\r\\n planEntryData,\\r\\n tokens,\\r\\n liquidationThresholds\\r\\n );\\r\\n\\r\\n // cover loss\\r\\n if (loss != 0) {\\r\\n ConverterStrategyBaseLib2.coverLossAndCheckResults(\\r\\n csbs,\\r\\n addr_[4],\\r\\n loss\\r\\n );\\r\\n }\\r\\n emit RebalancedDebt(loss, values_[1], 0);\\r\\n\\r\\n if (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED\\r\\n || (entryToPool == PairBasedStrategyLib.ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED && completed)\\r\\n ) {\\r\\n // We are going to enter to the pool: update lowerTick and upperTick, initialize tokenAmountsOut\\r\\n (pairState.lowerTick, pairState.upperTick) = UniswapV3DebtLib._calcNewTickRange(\\r\\n IUniswapV3Pool(pairState.pool),\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing\\r\\n );\\r\\n tokenAmountsOut = tokenAmounts;\\r\\n }\\r\\n return (completed, tokenAmountsOut); // hide warning\\r\\n }\\r\\n //endregion ------------------------------------------------ WithdrawByAgg\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4430a5a110ff7a45e1cc8930b9ec640e7f97305de498cd5647290ee1f512fa31\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x61489161003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c80637269cb3a116100ac578063a7aced091161007b578063a7aced0914610296578063adc43434146102a9578063af316733146102c9578063b6fda813146102f8578063bd85be291461031857600080fd5b80637269cb3a1461021357806380089367146102265780638fb5468e14610255578063911ec0531461026857600080fd5b80632b25a6cf116100e85780632b25a6cf1461019e57806334d2ec3d146101c05780633ae60bcb146101d357806354747e5b1461020057600080fd5b80630dc528a71461011a5780631749995614610147578063233545261461015a57806328f0aec41461017d575b600080fd5b61012d6101283660046136e0565b610338565b604080519283526020830191909152015b60405180910390f35b61012d61015536600461373c565b610354565b61016d610168366004613755565b610468565b604051901515815260200161013e565b61019061018b36600461373c565b6106f1565b60405190815260200161013e565b8180156101aa57600080fd5b506101be6101b9366004613785565b6107e8565b005b6101906101ce366004613885565b6108f1565b8180156101df57600080fd5b506101f36101ee366004613982565b610ab3565b60405161013e91906139e2565b61016d61020e3660046139fc565b610d69565b61016d610221366004613755565b610ddc565b81801561023257600080fd5b50610246610241366004613a19565b611093565b60405161013e93929190613ab3565b6101f361026336600461373c565b611387565b81801561027457600080fd5b50610288610283366004613b6e565b611591565b60405161013e929190613c1c565b6101f36102a4366004613982565b6117d8565b8180156102b557600080fd5b506101be6102c4366004613c37565b6119cf565b8180156102d557600080fd5b506102e96102e436600461373c565b611f6b565b60405161013e93929190613cc2565b81801561030457600080fd5b506101f3610313366004613d37565b612518565b61032b61032636600461373c565b6129f9565b60405161013e9190613e07565b60008061034786868686612b8a565b9150915094509492505050565b6040805160a08101825282546001600160a01b0390811682526003840154600160c81b8104600290810b60208501908152600160e01b909204810b848601908152600480880154630100000090046001600160801b0390811660608801908152306080890190815298516352bb7e6960e01b815288518816938101939093529451840b6024830152915190920b604483015291519091166064820152925116608483015260009182919073D398438a52fD230195861b9Af0B4Ab8e9b0006F2906352bb7e699060a4016040805180830381865af4158015610439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045d9190613e1a565b909590945092505050565b600080600061047685610354565b60038701549193509150600160a81b900460ff161561049157905b6002850154600386015460018701546040516370a0823160e01b81526001600160a01b0393841693928316929091169083906370a08231906104d7908490600401613e3e565b602060405180830381865afa1580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105189190613e52565b6105229086613e81565b6040516370a0823160e01b81529095506001600160a01b038316906370a0823190610551908490600401613e3e565b602060405180830381865afa15801561056e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105929190613e52565b61059c9085613e81565b935060006105a988612e57565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b81526004016105d99190613e3e565b602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a9190613e52565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b815260040161064a9190613e3e565b602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190613e52565b90506000670de0b6b3a76400006106a2848b613e94565b6106ac9190613ec1565b90506000670de0b6b3a76400006106c3848b613e94565b6106cd9190613ec1565b905060648211806106de5750606481115b9a50505050505050505050505b92915050565b805460038201546000916001600160a01b03169060ff600160a81b8204169083908190610740908590600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b9150915060008061075386858588612b8a565b909250905060006107648284613e81565b116040518060400160405280601081526020016f54532d3234207a65726f2076616c756560801b815250906107b55760405162461bcd60e51b81526004016107ac9190613e07565b60405180910390fd5b506107c08183613e81565b6107d282670de0b6b3a7640000613e94565b6107dc9190613ec1565b98975050505050505050565b6001830154604080516060810190915260228082526001600160a01b039092169182151591906148186020830139906108345760405162461bcd60e51b81526004016107ac9190613e07565b506003840154600160a81b900460ff1615610880576002840154610862906001600160a01b03168284612f46565b600384015461087b906001600160a01b03168285612f46565b6108b2565b6002840154610899906001600160a01b03168285612f46565b60038401546108b2906001600160a01b03168284612f46565b60408051848152602081018490527fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89910160405180910390a150505050565b600080846001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613ed5565b84519091506000805b82811015610aa557600087828151811061097b5761097b613ef2565b60200260200101519050896001600160a01b0316816001600160a01b0316036109ca578682815181106109b0576109b0613ef2565b6020026020010151836109c39190613e81565b9250610a94565b846001600160a01b031663a9dd14d68984815181106109eb576109eb613ef2565b60200260200101518c8a8681518110610a0657610a06613ef2565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015610a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a879190613e52565b610a919084613e81565b92505b50610a9e81613f08565b905061095f565b50925050505b949350505050565b8154600383015460048401546040805180820190915260158152745533532d372057726f6e67206c697175696469747960581b60208201526060936001600160a01b031692600160c81b8104600290810b93600160e01b830490910b926001600160801b03630100000090920482169260ff600160a81b90910416918816831015610b515760405162461bcd60e51b81526004016107ac9190613e07565b5060408051600280825260608201835290916020830190803683370190505060405163a34123a760e01b8152600286810b600483015285900b60248201526001600160801b03891660448201529096506001600160a01b0386169063a34123a79060640160408051808303816000875af1158015610bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf79190613e1a565b87600081518110610c0a57610c0a613ef2565b6020026020010188600181518110610c2457610c24613ef2565b6020908102919091010191909152526040516309e3d67b60e31b81526001600160a01b03861690634f1eb3d890610c6e903090889088906001600160801b03908190600401613f21565b60408051808303816000875af1158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190613f5e565b50610cbd90508783613f8d565b8860040160036101000a8154816001600160801b0302191690836001600160801b031602179055508015610d5e5785600181518110610cfe57610cfe613ef2565b602002602001015186600081518110610d1957610d19613ef2565b602002602001015187600081518110610d3457610d34613ef2565b6020026020010188600181518110610d4e57610d4e613ef2565b6020908102919091010191909152525b505050505092915050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190613fad565b62ffffff166064149050919050565b815460028301546040805163313ce56760e01b815290516000936001600160a01b0390811693859373E0D8b85C7Feb11b26e5A2466931088eC5DE7A7039363556ce728939092169163313ce567916004808201926020929091908290030181865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190613fe8565b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865af4158015610eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed59190613e52565b6003860154604051635620c32d60e11b81526001600160a01b0380861660048301529091166024820152909150600090829073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190613e52565b610f719190613e94565b90507306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe396351265e89878773BC79449e023737acFF022427C51e74F932B7F88A6317b13c95886040518263ffffffff1660e01b8152600401610fc69190613e3e565b602060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614003565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015260020b604482015260648101849052608401606060405180830381865af4158015611062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110869190614020565b5090979650505050505050565b604080516002808252606082810190935260009182918160200160208202803683370190505092506000866001815181106110d0576110d0613ef2565b6020026020010151111561137b57831561115757856001815181106110f7576110f7613ef2565b60200260200101518660008151811061111257611112613ef2565b60200260200101518760008151811061112d5761112d613ef2565b602002602001018860018151811061114757611147613ef2565b6020908102919091010191909152525b600073D398438a52fD230195861b9Af0B4Ab8e9b0006F26317c22c3c8b8b8b8b60008151811061118957611189613ef2565b60200260200101518c6001815181106111a4576111a4613ef2565b60200260200101516040518663ffffffff1660e01b81526004016111cc959493929190614071565b606060405180830381865af41580156111e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120d91906140a5565b8660008151811061122057611220613ef2565b602002602001018760018151811061123a5761123a613ef2565b6020908102919091010192909252919052604051633c8a7d8d60e01b815230600482015260028b810b60248301528a900b60448201526001600160801b038216606482015260a06084820152600060a48201529091506001600160a01b038b1690633c8a7d8d9060c40160408051808303816000875af11580156112c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e69190613e1a565b50506001600160801b03811692506112fe81876140d3565b91508415611379578360018151811061131957611319613ef2565b60200260200101518460008151811061133457611334613ef2565b60200260200101518560008151811061134f5761134f613ef2565b602002602001018660018151811061136957611369613ef2565b6020908102919091010191909152525b505b96509650969350505050565b60408051600280825260608083018452926020830190803683375050835460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa1580156113f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114169190614105565b505050506003860154600480880154604051630544f36560e31b815295965073D398438a52fD230195861b9Af0B4Ab8e9b0006F295632a279b28955061148894508793600160c81b8104600290810b94600160e01b909204900b92630100000090046001600160801b03169101614194565b6040805180830381865af41580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190613e1a565b836000815181106114db576114db613ef2565b60200260200101846001815181106114f5576114f5613ef2565b6020908102919091010191909152526003830154600160a81b900460ff161561158b578160018151811061152b5761152b613ef2565b60200260200101518260008151811061154657611546613ef2565b60200260200101518360008151811061156157611561613ef2565b602002602001018460018151811061157b5761157b613ef2565b6020908102919091010191909152525b50919050565b60408051808201825260028401546001600160a01b0390811682526003850154166020820152905163bd13c52960e01b8152600091606091888301359190839085907306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe399063bd13c52990611607908f908f908f908f908a908f906004016141d0565b600060405180830381865af4158015611624573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164c91908101906142e2565b9197509250905080156116ef5773C92346a144fa75b45b0eDAe966FEAA0E30C82c556326eadaa38e8e600460200201602081019061168a91906139fc565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044810184905260640160006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505b6040805182815260208d8101359082015260008183015290517f3715d08a7dcc9d792a5a426f62429b9f889a7b140004f9f85190a48485695cf19181900360600190a1600184148061174957506002841480156117495750855b156117c85787546003890154611789916001600160a01b031690600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b60038a01805465ffffffffffff60c81b1916600160e01b62ffffff9384160262ffffff60c81b191617600160c81b939092169290920217905590935083905b5050505097509795505050505050565b60408051600280825260608083018452926020830190803683375050845460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa158015611843573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118679190614105565b5050506003880154604051630544f36560e31b815294955073D398438a52fD230195861b9Af0B4Ab8e9b0006F294632a279b2894506118c59350869250600160c81b8204600290810b92600160e01b9004900b908990600401614194565b6040805180830381865af41580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190613e1a565b8360008151811061191857611918613ef2565b602002602001018460018151811061193257611932613ef2565b6020908102919091010191909152526003840154600160a81b900460ff16156119c8578160018151811061196857611968613ef2565b60200260200101518260008151811061198357611983613ef2565b60200260200101518360008151811061199e5761199e613ef2565b60200260200101846001815181106119b8576119b8613ef2565b6020908102919091010191909152525b5092915050565b60408051808201909152601181527054532d31207a65726f206164647265737360781b60208201526001600160a01b038616611a1e5760405162461bcd60e51b81526004016107ac9190613e07565b506000856001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190613ed5565b90506000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190613ed5565b9050611af36135dc565b600073D398438a52fD230195861b9Af0B4Ab8e9b0006F263ea8668158a6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190613fad565b6040516001600160e01b031960e084901b16815262ffffff9091166004820152602401602060405180830381865af4158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd59190614003565b90508760020b600014611caa5780611bed818a61433b565b611bf79190614375565b60020b8860020b146040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525090611c535760405162461bcd60e51b81526004016107ac9190613e07565b5080611c5f818961433b565b611c699190614375565b60020b8760020b1460405180606001604052806022815260200161483a6022913990611ca85760405162461bcd60e51b81526004016107ac9190613e07565b505b600281810b80845260405163362ad1e560e11b81526001600160a01b038c166004820152918a900b6024830152604482015273BC79449e023737acFF022427C51e74F932B7F88A90636c55a3ca906064016040805180830381865af4158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614395565b600290810b60408086019190915291810b6020808601919091529089900b60608086019190915282516080810184526001600160a01b038d811682528a81169382019390935287831693810193909352908516908201527306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39915063b8b4a449908c9084611dbb8d610d69565b896040518663ffffffff1660e01b8152600401611ddc9594939291906143c4565b60006040518083038186803b158015611df457600080fd5b505af4158015611e08573d6000803e3d6000fd5b505050506000896001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e709190613ed5565b60405163095ea7b360e01b81526001600160a01b03808316600483015260001960248301529192509085169063095ea7b3906044016020604051808303816000875af1158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190614441565b5060405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015284169063095ea7b3906044016020604051808303816000875af1158015611f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5d9190614441565b505050505050505050505050565b6001810154815460038301546040805160028082526060808301845295869586956001600160a01b03928316959290911693600160c81b8204840b93600160e01b909204820b92909190602083019080368337505050600289015481519198506001600160a01b0316908890600090611fe657611fe6613ef2565b6001600160a01b039283166020918202929092010152600389015488519116908890600190811061201957612019613ef2565b6001600160a01b039290921660209283029190910182015260408051600280825260608201835290929091908301908036833701905050945060005b87518110156121135787818151811061207057612070613ef2565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120a39190613e3e565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e49190613e52565b8682815181106120f6576120f6613ef2565b60209081029190910101528061210b81613f08565b915050612055565b506040805160028082526060820183529091602083019080368337019050506004890154909650630100000090046001600160801b03161561229f5760405163a34123a760e01b8152600283810b600483015282900b6024820152600060448201526001600160a01b0384169063a34123a79060640160408051808303816000875af11580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613e1a565b50506040516309e3d67b60e31b81526001600160a01b03841690634f1eb3d890612208903090869086906001600160801b03908190600401613f21565b60408051808303816000875af1158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a9190613f5e565b816001600160801b03169150806001600160801b031690508760008151811061227557612275613ef2565b602002602001018860018151811061228f5761228f613ef2565b6020908102919091010191909152525b7fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89866000815181106122d3576122d3613ef2565b6020026020010151876001815181106122ee576122ee613ef2565b602002602001015160405161230d929190918252602082015260400190565b60405180910390a16003880154600160a81b900460ff161561239c578560018151811061233c5761233c613ef2565b60200260200101518660008151811061235757612357613ef2565b60200260200101518760008151811061237257612372613ef2565b602002602001018860018151811061238c5761238c613ef2565b6020908102919091010191909152525b60005b875181101561250c5760008882815181106123bc576123bc613ef2565b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016123ef9190613e3e565b602060405180830381865afa15801561240c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124309190613e52565b905080156124fb5788828151811061244a5761244a613ef2565b60209081029190910101516040516323b872dd60e01b81526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf9190614441565b50808883815181106124e3576124e3613ef2565b602002602001018181516124f79190613e81565b9052505b5061250581613f08565b905061239f565b50505050509193909250565b60606125226135fa565b61253a8161253360208b018b6139fc565b8b86612f9d565b61014081015160408083015160038c01549151635620c32d60e11b81526001600160a01b0391821660048201529116602482015273D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af41580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190613e52565b6125d89190613e94565b61012082015260408082015190516317b13c9560e01b8152600091829173BC79449e023737acFF022427C51e74F932B7F88A916317b13c959161261e9190600401613e3e565b602060405180830381865af415801561263b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265f9190614003565b60208401516101208501516040516351265e8960e01b8152600481018f90526001600160a01b039092166024830152600283900b604483015260648201529091507306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39906351265e8990608401606060405180830381865af41580156126dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127009190614020565b8560e001866101000182600381111561271b5761271b61445e565b600381111561272c5761272c61445e565b905291151590915250915081156127b2577306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39634aa009158c8560e001518661010001516040518463ffffffff1660e01b815260040161278193929190614474565b60006040518083038186803b15801561279957600080fd5b505af41580156127ad573d6000803e3d6000fd5b505050505b8515806127bc5750815b6040518060400160405280601981526020017f5533532d39204e6f20726562616c616e6365206e656564656400000000000000815250906128105760405162461bcd60e51b81526004016107ac9190613e07565b5081156129ea5773BC79449e023737acFF022427C51e74F932B7F88A63e4ee4bf78b8d8b8d8c8960c00151886040518863ffffffff1660e01b815260040161285e97969594939291906144d8565b60006040518083038186803b15801561287657600080fd5b505af415801561288a573d6000803e3d6000fd5b50505050600073C92346a144fa75b45b0eDAe966FEAA0E30C82c5563ac2a37d685602001518c876060015188608001518960c001516040518663ffffffff1660e01b81526004016128df95949392919061455e565b600060405180830381865af41580156128fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129249190810190614592565b9550905080156129a8576040516326eadaa360e01b8152600481018e90526001600160a01b03891660248201526044810182905273C92346a144fa75b45b0eDAe966FEAA0E30C82c55906326eadaa39060640160006040518083038186803b15801561298f57600080fd5b505af41580156129a3573d6000803e3d6000fd5b505050505b60408051828152602081018b905260008183015290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a1505b50505098975050505050505050565b6002810154604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015612a45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a6d91908101906145d8565b8260030160009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ac2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aea91908101906145d8565b83546040805163ddca3f4360e01b81529051612b62926001600160a01b03169163ddca3f439160048083019260209291908290030181865afa158015612b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b589190613fad565b62ffffff16613194565b604051602001612b749392919061464e565b6040516020818303038152906040529050919050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf19190613ed5565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613e52565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190613fe8565b60ff169050816000612cf483600a6147a3565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015290915081612d3c5760405162461bcd60e51b81526004016107ac9190613e07565b5060008073D398438a52fD230195861b9Af0B4Ab8e9b0006F26317c22c3c8e8e8e88886040518663ffffffff1660e01b8152600401612d7f959493929190614071565b606060405180830381865af4158015612d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc091906140a5565b509150915089612e0957612ddc82670de0b6b3a7640000613e94565b8387612df084670de0b6b3a7640000613e94565b612dfa9190613e94565b612e049190613ec1565b612e43565b8286612e1d83670de0b6b3a7640000613e94565b612e279190613e94565b612e319190613ec1565b612e4383670de0b6b3a7640000613e94565b985098505050505050505094509492505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebb9190613ed5565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106eb9190613ed5565b6000806000612f2a87613294565b9050612f3881878787613305565b925092505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612f989084906133cf565b505050565b81546001600160a01b0316604080860191909152805160608101909152600583018054829060ff166003811115612fd657612fd661445e565b6003811115612fe757612fe761445e565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161300757505050918352505060408051608081019182905260209092019190600584019060049082845b815481526020019060010190808311613040575050509190925250505084526001600160a01b03838116602080870191909152600284015482166060870181905260038501549283166080880152600160a01b90920460ff16151560a0870152600091825282905260409020546130b6906134a1565b60c08501515260808401516001600160a01b03166000908152602082905260409020546130e2906134a1565b60c08501516001602002018181525050600084606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315a9190613fe8565b60ff1690506012811061316e576001613184565b6131798160126147af565b61318490600a6147a3565b6101409095019490945250505050565b6060816000036131bb5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156131e557806131cf81613f08565b91506131de9050600a83613ec1565b91506131bf565b6000816001600160401b038111156131ff576131ff6137b1565b6040519080825280601f01601f191660200182016040528015613229576020820181803683370190505b5090505b8415610aab5761323e6001836147af565b915061324b600a866147c2565b613256906030613e81565b60f81b81838151811061326b5761326b613ef2565b60200101906001600160f81b031916908160001a90535061328d600a86613ec1565b945061322d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f89190614105565b5093979650505050505050565b6000808061331386866147d6565b905060008460020b8260020b146133345761332f60028361433b565b613337565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b60448201529091507306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe399063cd8e20e7906064016040805180830381865af415801561339c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c09190614395565b93509350505094509492505050565b6000613424826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134b99092919063ffffffff16565b805190915015612f9857808060200190518101906134429190614441565b612f985760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ac565b600081156134af57816106eb565b620186a092915050565b6060610aab848460008585600080866001600160a01b031685876040516134e091906147fb565b60006040518083038185875af1925050503d806000811461351d576040519150601f19603f3d011682016040523d82523d6000602084013e613522565b606091505b50915091506135338783838761353e565b979650505050505050565b606083156135ad5782516000036135a6576001600160a01b0385163b6135a65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107ac565b5081610aab565b610aab83838151156135c25781518083602001fd5b8060405162461bcd60e51b81526004016107ac9190613e07565b60405180608001604052806004906020820280368337509192915050565b60405180610160016040528061360e613660565b815260006020820181905260408201819052606082018190526080820181905260a082015260c00161363e61368d565b8152600060208201819052604082018190526060820181905260809091015290565b6040805160608101909152806000815260200161367b6135dc565b81526020016136886135dc565b905290565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146136c057600080fd5b50565b8060020b81146136c057600080fd5b80151581146136c057600080fd5b600080600080608085870312156136f657600080fd5b8435613701816136ab565b93506020850135613711816136c3565b92506040850135613721816136c3565b91506060850135613731816136d2565b939692955090935050565b60006020828403121561374e57600080fd5b5035919050565b6000806040838503121561376857600080fd5b82359150602083013561377a816136ab565b809150509250929050565b60008060006060848603121561379a57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137ef576137ef6137b1565b604052919050565b60006001600160401b03821115613810576138106137b1565b5060051b60200190565b600082601f83011261382b57600080fd5b8135602061384061383b836137f7565b6137c7565b82815260059290921b8401810191818101908684111561385f57600080fd5b8286015b8481101561387a5780358352918301918301613863565b509695505050505050565b6000806000806080858703121561389b57600080fd5b84356138a6816136ab565b93506020858101356138b7816136ab565b935060408601356001600160401b03808211156138d357600080fd5b818801915088601f8301126138e757600080fd5b81356138f561383b826137f7565b81815260059190911b8301840190848101908b83111561391457600080fd5b938501935b8285101561393b57843561392c816136ab565b82529385019390850190613919565b96505050606088013592508083111561395357600080fd5b50506139618782880161381a565b91505092959194509250565b6001600160801b03811681146136c057600080fd5b6000806040838503121561399557600080fd5b82359150602083013561377a8161396d565b600081518084526020808501945080840160005b838110156139d7578151875295820195908201906001016139bb565b509495945050505050565b6020815260006139f560208301846139a7565b9392505050565b600060208284031215613a0e57600080fd5b81356139f5816136ab565b60008060008060008060c08789031215613a3257600080fd5b8635613a3d816136ab565b95506020870135613a4d816136c3565b94506040870135613a5d816136c3565b935060608701356001600160401b03811115613a7857600080fd5b613a8489828a0161381a565b9350506080870135613a958161396d565b915060a0870135613aa5816136d2565b809150509295509295509295565b606081526000613ac660608301866139a7565b90508360208301526001600160801b0383166040830152949350505050565b80608081018310156106eb57600080fd5b60006001600160401b03821115613b0f57613b0f6137b1565b50601f01601f191660200190565b600082601f830112613b2e57600080fd5b8135613b3c61383b82613af6565b818152846020838601011115613b5157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060006101c0888a031215613b8a57600080fd5b8735965060c0880189811115613b9f57600080fd5b602089019650613baf8a82613ae5565b9550506101408801356001600160401b0380821115613bcd57600080fd5b613bd98b838c01613b1d565b95506101608a0135915080821115613bf057600080fd5b50613bfd8a828b01613b1d565b93505061018088013591506101a0880135905092959891949750929550565b8215158152604060208201526000610aab60408301846139a7565b6000806000806000806000610140888a031215613c5357600080fd5b873596506020880135613c65816136ab565b95506040880135613c75816136ab565b94506060880135613c85816136c3565b93506080880135613c95816136c3565b925060a0880135613ca5816136ab565b9150613cb48960c08a01613ae5565b905092959891949750929550565b606080825284519082018190526000906020906080840190828801845b82811015613d045781516001600160a01b031684529284019290840190600101613cdf565b50505083810382850152613d1881876139a7565b9150508281036040840152613d2d81856139a7565b9695505050505050565b600080600080600080600080610120898b031215613d5457600080fd5b8835975060208901359650608089018a811115613d7057600080fd5b60408a01965035945060a0890135935060c0890135613d8e816136ab565b925060e0890135613d9e816136d2565b8092505061010089013590509295985092959890939650565b60005b83811015613dd2578181015183820152602001613dba565b50506000910152565b60008151808452613df3816020860160208601613db7565b601f01601f19169290920160200192915050565b6020815260006139f56020830184613ddb565b60008060408385031215613e2d57600080fd5b505080516020909101519092909150565b6001600160a01b0391909116815260200190565b600060208284031215613e6457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106eb576106eb613e6b565b80820281158282048414176106eb576106eb613e6b565b634e487b7160e01b600052601260045260246000fd5b600082613ed057613ed0613eab565b500490565b600060208284031215613ee757600080fd5b81516139f5816136ab565b634e487b7160e01b600052603260045260246000fd5b600060018201613f1a57613f1a613e6b565b5060010190565b6001600160a01b03959095168552600293840b60208601529190920b60408401526001600160801b03918216606084015216608082015260a00190565b60008060408385031215613f7157600080fd5b8251613f7c8161396d565b602084015190925061377a8161396d565b6001600160801b038281168282160390808211156119c8576119c8613e6b565b600060208284031215613fbf57600080fd5b815162ffffff811681146139f557600080fd5b805160ff81168114613fe357600080fd5b919050565b600060208284031215613ffa57600080fd5b6139f582613fd2565b60006020828403121561401557600080fd5b81516139f5816136c3565b60008060006060848603121561403557600080fd5b8351614040816136d2565b6020850151909350614051816136d2565b60408501519092506004811061406657600080fd5b809150509250925092565b6001600160a01b03959095168552600293840b60208601529190920b60408401526060830191909152608082015260a00190565b6000806000606084860312156140ba57600080fd5b835192506020840151915060408401516140668161396d565b6001600160801b038181168382160190808211156119c8576119c8613e6b565b805161ffff81168114613fe357600080fd5b600080600080600080600060e0888a03121561412057600080fd5b875161412b816136ab565b602089015190975061413c816136c3565b955061414a604089016140f3565b9450614158606089016140f3565b9350614166608089016140f3565b925061417460a08901613fd2565b915060c0880151614184816136d2565b8091505092959891949750929550565b6001600160a01b03949094168452600292830b6020850152910b60408301526001600160801b0316606082015260800190565b60808183375050565b60006101c08289835b600581101561420b5781356141ed816136ab565b6001600160a01b0316835260209283019291909101906001016141d9565b50505060808860a08501378061012084015261422981840188613ddb565b905082810361014084015261423e8187613ddb565b91505061016082018460005b60028110156142725781516001600160a01b031683526020928301929091019060010161424a565b505050826101a0830152979650505050505050565b600082601f83011261429857600080fd5b815160206142a861383b836137f7565b82815260059290921b840181019181810190868411156142c757600080fd5b8286015b8481101561387a57805183529183019183016142cb565b6000806000606084860312156142f757600080fd5b8351614302816136d2565b60208501519093506001600160401b0381111561431e57600080fd5b61432a86828701614287565b925050604084015190509250925092565b60008160020b8360020b8061435257614352613eab565b627fffff1982146000198214161561436c5761436c613e6b565b90059392505050565b60008260020b8260020b028060020b91508082146119c8576119c8613e6b565b600080604083850312156143a857600080fd5b82516143b3816136c3565b602084015190925061377a816136c3565b8581526101c0810160208083018760005b60048110156143fb5781516001600160a01b0316835291830191908301906001016143d5565b50505060a083018660005b600481101561442657815160020b83529183019190830190600101614406565b50505050831515610120830152613d2d6101408301846141c7565b60006020828403121561445357600080fd5b81516139f5816136d2565b634e487b7160e01b600052602160045260246000fd5b838152821515602082015260608101600483106144a157634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b8060005b60028110156144d25781518452602093840193909101906001016144b3565b50505050565b6101208101818960005b60028110156145145781356144f6816136ab565b6001600160a01b0316835260209283019291909101906001016144e2565b5050506040820188905260608201879052608082018690526001600160a01b03851660a083015261454860c08301856144af565b8260020b61010083015298975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c08101613d2d60808301846144af565b600080604083850312156145a557600080fd5b8251915060208301516001600160401b038111156145c257600080fd5b6145ce85828601614287565b9150509250929050565b6000602082840312156145ea57600080fd5b81516001600160401b0381111561460057600080fd5b8201601f8101841361461157600080fd5b805161461f61383b82613af6565b81815285602083850101111561463457600080fd5b614645826020830160208601613db7565b95945050505050565b6502ab734ab19960d51b81526000845161466f816006850160208901613db7565b602f60f81b6006918401918201528451614690816007840160208901613db7565b602d60f81b6007929091019182015283516146b2816008840160208801613db7565b0160080195945050505050565b600181815b808511156146fa5781600019048211156146e0576146e0613e6b565b808516156146ed57918102915b93841c93908002906146c4565b509250929050565b600082614711575060016106eb565b8161471e575060006106eb565b8160018114614734576002811461473e5761475a565b60019150506106eb565b60ff84111561474f5761474f613e6b565b50506001821b6106eb565b5060208310610133831016604e8410600b841016171561477d575081810a6106eb565b61478783836146bf565b806000190482111561479b5761479b613e6b565b029392505050565b60006139f58383614702565b818103818111156106eb576106eb613e6b565b6000826147d1576147d1613eab565b500690565b600282810b9082900b03627fffff198112627fffff821317156106eb576106eb613e6b565b6000825161480d818460208701613db7565b919091019291505056fe5533532d3133205a65726f2073747261746567792070726f66697420686f6c6465725042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a264697066735822122083da58e5269555d01b1905b58be1c345b274f3f88d5186dbbc1e8db6862e15f864736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106101155760003560e01c80637269cb3a116100ac578063a7aced091161007b578063a7aced0914610296578063adc43434146102a9578063af316733146102c9578063b6fda813146102f8578063bd85be291461031857600080fd5b80637269cb3a1461021357806380089367146102265780638fb5468e14610255578063911ec0531461026857600080fd5b80632b25a6cf116100e85780632b25a6cf1461019e57806334d2ec3d146101c05780633ae60bcb146101d357806354747e5b1461020057600080fd5b80630dc528a71461011a5780631749995614610147578063233545261461015a57806328f0aec41461017d575b600080fd5b61012d6101283660046136e0565b610338565b604080519283526020830191909152015b60405180910390f35b61012d61015536600461373c565b610354565b61016d610168366004613755565b610468565b604051901515815260200161013e565b61019061018b36600461373c565b6106f1565b60405190815260200161013e565b8180156101aa57600080fd5b506101be6101b9366004613785565b6107e8565b005b6101906101ce366004613885565b6108f1565b8180156101df57600080fd5b506101f36101ee366004613982565b610ab3565b60405161013e91906139e2565b61016d61020e3660046139fc565b610d69565b61016d610221366004613755565b610ddc565b81801561023257600080fd5b50610246610241366004613a19565b611093565b60405161013e93929190613ab3565b6101f361026336600461373c565b611387565b81801561027457600080fd5b50610288610283366004613b6e565b611591565b60405161013e929190613c1c565b6101f36102a4366004613982565b6117d8565b8180156102b557600080fd5b506101be6102c4366004613c37565b6119cf565b8180156102d557600080fd5b506102e96102e436600461373c565b611f6b565b60405161013e93929190613cc2565b81801561030457600080fd5b506101f3610313366004613d37565b612518565b61032b61032636600461373c565b6129f9565b60405161013e9190613e07565b60008061034786868686612b8a565b9150915094509492505050565b6040805160a08101825282546001600160a01b0390811682526003840154600160c81b8104600290810b60208501908152600160e01b909204810b848601908152600480880154630100000090046001600160801b0390811660608801908152306080890190815298516352bb7e6960e01b815288518816938101939093529451840b6024830152915190920b604483015291519091166064820152925116608483015260009182919073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__906352bb7e699060a4016040805180830381865af4158015610439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061045d9190613e1a565b909590945092505050565b600080600061047685610354565b60038701549193509150600160a81b900460ff161561049157905b6002850154600386015460018701546040516370a0823160e01b81526001600160a01b0393841693928316929091169083906370a08231906104d7908490600401613e3e565b602060405180830381865afa1580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105189190613e52565b6105229086613e81565b6040516370a0823160e01b81529095506001600160a01b038316906370a0823190610551908490600401613e3e565b602060405180830381865afa15801561056e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105929190613e52565b61059c9085613e81565b935060006105a988612e57565b90506000816001600160a01b031663b3596f07866040518263ffffffff1660e01b81526004016105d99190613e3e565b602060405180830381865afa1580156105f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061a9190613e52565b90506000826001600160a01b031663b3596f07866040518263ffffffff1660e01b815260040161064a9190613e3e565b602060405180830381865afa158015610667573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068b9190613e52565b90506000670de0b6b3a76400006106a2848b613e94565b6106ac9190613ec1565b90506000670de0b6b3a76400006106c3848b613e94565b6106cd9190613ec1565b905060648211806106de5750606481115b9a50505050505050505050505b92915050565b805460038201546000916001600160a01b03169060ff600160a81b8204169083908190610740908590600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b9150915060008061075386858588612b8a565b909250905060006107648284613e81565b116040518060400160405280601081526020016f54532d3234207a65726f2076616c756560801b815250906107b55760405162461bcd60e51b81526004016107ac9190613e07565b60405180910390fd5b506107c08183613e81565b6107d282670de0b6b3a7640000613e94565b6107dc9190613ec1565b98975050505050505050565b6001830154604080516060810190915260228082526001600160a01b039092169182151591906148186020830139906108345760405162461bcd60e51b81526004016107ac9190613e07565b506003840154600160a81b900460ff1615610880576002840154610862906001600160a01b03168284612f46565b600384015461087b906001600160a01b03168285612f46565b6108b2565b6002840154610899906001600160a01b03168285612f46565b60038401546108b2906001600160a01b03168284612f46565b60408051848152602081018490527fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89910160405180910390a150505050565b600080846001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613ed5565b84519091506000805b82811015610aa557600087828151811061097b5761097b613ef2565b60200260200101519050896001600160a01b0316816001600160a01b0316036109ca578682815181106109b0576109b0613ef2565b6020026020010151836109c39190613e81565b9250610a94565b846001600160a01b031663a9dd14d68984815181106109eb576109eb613ef2565b60200260200101518c8a8681518110610a0657610a06613ef2565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401602060405180830381865afa158015610a63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a879190613e52565b610a919084613e81565b92505b50610a9e81613f08565b905061095f565b50925050505b949350505050565b8154600383015460048401546040805180820190915260158152745533532d372057726f6e67206c697175696469747960581b60208201526060936001600160a01b031692600160c81b8104600290810b93600160e01b830490910b926001600160801b03630100000090920482169260ff600160a81b90910416918816831015610b515760405162461bcd60e51b81526004016107ac9190613e07565b5060408051600280825260608201835290916020830190803683370190505060405163a34123a760e01b8152600286810b600483015285900b60248201526001600160801b03891660448201529096506001600160a01b0386169063a34123a79060640160408051808303816000875af1158015610bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf79190613e1a565b87600081518110610c0a57610c0a613ef2565b6020026020010188600181518110610c2457610c24613ef2565b6020908102919091010191909152526040516309e3d67b60e31b81526001600160a01b03861690634f1eb3d890610c6e903090889088906001600160801b03908190600401613f21565b60408051808303816000875af1158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190613f5e565b50610cbd90508783613f8d565b8860040160036101000a8154816001600160801b0302191690836001600160801b031602179055508015610d5e5785600181518110610cfe57610cfe613ef2565b602002602001015186600081518110610d1957610d19613ef2565b602002602001015187600081518110610d3457610d34613ef2565b6020026020010188600181518110610d4e57610d4e613ef2565b6020908102919091010191909152525b505050505092915050565b6000816001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcd9190613fad565b62ffffff166064149050919050565b815460028301546040805163313ce56760e01b815290516000936001600160a01b0390811693859373__$79fe6ec7a3db45dafbed12dca1c6dad764$__9363556ce728939092169163313ce567916004808201926020929091908290030181865afa158015610e4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e739190613fe8565b6040516001600160e01b031960e084901b16815260ff9091166004820152602401602060405180830381865af4158015610eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed59190613e52565b6003860154604051635620c32d60e11b81526001600160a01b0380861660048301529091166024820152909150600090829073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015610f43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f679190613e52565b610f719190613e94565b905073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__6351265e89878773__$105aa07724e80e292e8a4b4cc62d6ec972$__6317b13c95886040518263ffffffff1660e01b8152600401610fc69190613e3e565b602060405180830381865af4158015610fe3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110079190614003565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b03909116602483015260020b604482015260648101849052608401606060405180830381865af4158015611062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110869190614020565b5090979650505050505050565b604080516002808252606082810190935260009182918160200160208202803683370190505092506000866001815181106110d0576110d0613ef2565b6020026020010151111561137b57831561115757856001815181106110f7576110f7613ef2565b60200260200101518660008151811061111257611112613ef2565b60200260200101518760008151811061112d5761112d613ef2565b602002602001018860018151811061114757611147613ef2565b6020908102919091010191909152525b600073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__6317c22c3c8b8b8b8b60008151811061118957611189613ef2565b60200260200101518c6001815181106111a4576111a4613ef2565b60200260200101516040518663ffffffff1660e01b81526004016111cc959493929190614071565b606060405180830381865af41580156111e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120d91906140a5565b8660008151811061122057611220613ef2565b602002602001018760018151811061123a5761123a613ef2565b6020908102919091010192909252919052604051633c8a7d8d60e01b815230600482015260028b810b60248301528a900b60448201526001600160801b038216606482015260a06084820152600060a48201529091506001600160a01b038b1690633c8a7d8d9060c40160408051808303816000875af11580156112c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e69190613e1a565b50506001600160801b03811692506112fe81876140d3565b91508415611379578360018151811061131957611319613ef2565b60200260200101518460008151811061133457611334613ef2565b60200260200101518560008151811061134f5761134f613ef2565b602002602001018660018151811061136957611369613ef2565b6020908102919091010191909152525b505b96509650969350505050565b60408051600280825260608083018452926020830190803683375050835460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa1580156113f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114169190614105565b505050506003860154600480880154604051630544f36560e31b815295965073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__95632a279b28955061148894508793600160c81b8104600290810b94600160e01b909204900b92630100000090046001600160801b03169101614194565b6040805180830381865af41580156114a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c89190613e1a565b836000815181106114db576114db613ef2565b60200260200101846001815181106114f5576114f5613ef2565b6020908102919091010191909152526003830154600160a81b900460ff161561158b578160018151811061152b5761152b613ef2565b60200260200101518260008151811061154657611546613ef2565b60200260200101518360008151811061156157611561613ef2565b602002602001018460018151811061157b5761157b613ef2565b6020908102919091010191909152525b50919050565b60408051808201825260028401546001600160a01b0390811682526003850154166020820152905163bd13c52960e01b81526000916060918883013591908390859073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063bd13c52990611607908f908f908f908f908a908f906004016141d0565b600060405180830381865af4158015611624573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261164c91908101906142e2565b9197509250905080156116ef5773__$8f1afe7577f9ab973017c74eca19b86f3c$__6326eadaa38e8e600460200201602081019061168a91906139fc565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044810184905260640160006040518083038186803b1580156116d657600080fd5b505af41580156116ea573d6000803e3d6000fd5b505050505b6040805182815260208d8101359082015260008183015290517f3715d08a7dcc9d792a5a426f62429b9f889a7b140004f9f85190a48485695cf19181900360600190a1600184148061174957506002841480156117495750855b156117c85787546003890154611789916001600160a01b031690600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b612f1c565b60038a01805465ffffffffffff60c81b1916600160e01b62ffffff9384160262ffffff60c81b191617600160c81b939092169290920217905590935083905b5050505097509795505050505050565b60408051600280825260608083018452926020830190803683375050845460408051633850c7bd60e01b815290519394506000936001600160a01b039092169250633850c7bd9160048083019260e09291908290030181865afa158015611843573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118679190614105565b5050506003880154604051630544f36560e31b815294955073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__94632a279b2894506118c59350869250600160c81b8204600290810b92600160e01b9004900b908990600401614194565b6040805180830381865af41580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190613e1a565b8360008151811061191857611918613ef2565b602002602001018460018151811061193257611932613ef2565b6020908102919091010191909152526003840154600160a81b900460ff16156119c8578160018151811061196857611968613ef2565b60200260200101518260008151811061198357611983613ef2565b60200260200101518360008151811061199e5761199e613ef2565b60200260200101846001815181106119b8576119b8613ef2565b6020908102919091010191909152525b5092915050565b60408051808201909152601181527054532d31207a65726f206164647265737360781b60208201526001600160a01b038616611a1e5760405162461bcd60e51b81526004016107ac9190613e07565b506000856001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190613ed5565b90506000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190613ed5565b9050611af36135dc565b600073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__63ea8668158a6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190613fad565b6040516001600160e01b031960e084901b16815262ffffff9091166004820152602401602060405180830381865af4158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd59190614003565b90508760020b600014611caa5780611bed818a61433b565b611bf79190614375565b60020b8860020b146040518060400160405280601981526020017f5042532d3320496e636f7272656374207469636b52616e67650000000000000081525090611c535760405162461bcd60e51b81526004016107ac9190613e07565b5080611c5f818961433b565b611c699190614375565b60020b8760020b1460405180606001604052806022815260200161483a6022913990611ca85760405162461bcd60e51b81526004016107ac9190613e07565b505b600281810b80845260405163362ad1e560e11b81526001600160a01b038c166004820152918a900b6024830152604482015273__$105aa07724e80e292e8a4b4cc62d6ec972$__90636c55a3ca906064016040805180830381865af4158015611d17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3b9190614395565b600290810b60408086019190915291810b6020808601919091529089900b60608086019190915282516080810184526001600160a01b038d811682528a811693820193909352878316938101939093529085169082015273__$b1ba452cecccdd06eb05ace2d0a762c7e1$__915063b8b4a449908c9084611dbb8d610d69565b896040518663ffffffff1660e01b8152600401611ddc9594939291906143c4565b60006040518083038186803b158015611df457600080fd5b505af4158015611e08573d6000803e3d6000fd5b505050506000896001600160a01b0316634046ebae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e709190613ed5565b60405163095ea7b360e01b81526001600160a01b03808316600483015260001960248301529192509085169063095ea7b3906044016020604051808303816000875af1158015611ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee89190614441565b5060405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015284169063095ea7b3906044016020604051808303816000875af1158015611f39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5d9190614441565b505050505050505050505050565b6001810154815460038301546040805160028082526060808301845295869586956001600160a01b03928316959290911693600160c81b8204840b93600160e01b909204820b92909190602083019080368337505050600289015481519198506001600160a01b0316908890600090611fe657611fe6613ef2565b6001600160a01b039283166020918202929092010152600389015488519116908890600190811061201957612019613ef2565b6001600160a01b039290921660209283029190910182015260408051600280825260608201835290929091908301908036833701905050945060005b87518110156121135787818151811061207057612070613ef2565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016120a39190613e3e565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e49190613e52565b8682815181106120f6576120f6613ef2565b60209081029190910101528061210b81613f08565b915050612055565b506040805160028082526060820183529091602083019080368337019050506004890154909650630100000090046001600160801b03161561229f5760405163a34123a760e01b8152600283810b600483015282900b6024820152600060448201526001600160a01b0384169063a34123a79060640160408051808303816000875af11580156121a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cb9190613e1a565b50506040516309e3d67b60e31b81526001600160a01b03841690634f1eb3d890612208903090869086906001600160801b03908190600401613f21565b60408051808303816000875af1158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a9190613f5e565b816001600160801b03169150806001600160801b031690508760008151811061227557612275613ef2565b602002602001018860018151811061228f5761228f613ef2565b6020908102919091010191909152525b7fd809a30c675e811f2837e53a49b9409406bb7e6f808658eef60d09ac30579e89866000815181106122d3576122d3613ef2565b6020026020010151876001815181106122ee576122ee613ef2565b602002602001015160405161230d929190918252602082015260400190565b60405180910390a16003880154600160a81b900460ff161561239c578560018151811061233c5761233c613ef2565b60200260200101518660008151811061235757612357613ef2565b60200260200101518760008151811061237257612372613ef2565b602002602001018860018151811061238c5761238c613ef2565b6020908102919091010191909152525b60005b875181101561250c5760008882815181106123bc576123bc613ef2565b60200260200101516001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016123ef9190613e3e565b602060405180830381865afa15801561240c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124309190613e52565b905080156124fb5788828151811061244a5761244a613ef2565b60209081029190910101516040516323b872dd60e01b81526001600160a01b03888116600483015230602483015260448201849052909116906323b872dd906064016020604051808303816000875af11580156124ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cf9190614441565b50808883815181106124e3576124e3613ef2565b602002602001018181516124f79190613e81565b9052505b5061250581613f08565b905061239f565b50505050509193909250565b60606125226135fa565b61253a8161253360208b018b6139fc565b8b86612f9d565b61014081015160408083015160038c01549151635620c32d60e11b81526001600160a01b0391821660048201529116602482015273__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af41580156125aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ce9190613e52565b6125d89190613e94565b61012082015260408082015190516317b13c9560e01b8152600091829173__$105aa07724e80e292e8a4b4cc62d6ec972$__916317b13c959161261e9190600401613e3e565b602060405180830381865af415801561263b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061265f9190614003565b60208401516101208501516040516351265e8960e01b8152600481018f90526001600160a01b039092166024830152600283900b6044830152606482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__906351265e8990608401606060405180830381865af41580156126dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127009190614020565b8560e001866101000182600381111561271b5761271b61445e565b600381111561272c5761272c61445e565b905291151590915250915081156127b25773__$b1ba452cecccdd06eb05ace2d0a762c7e1$__634aa009158c8560e001518661010001516040518463ffffffff1660e01b815260040161278193929190614474565b60006040518083038186803b15801561279957600080fd5b505af41580156127ad573d6000803e3d6000fd5b505050505b8515806127bc5750815b6040518060400160405280601981526020017f5533532d39204e6f20726562616c616e6365206e656564656400000000000000815250906128105760405162461bcd60e51b81526004016107ac9190613e07565b5081156129ea5773__$105aa07724e80e292e8a4b4cc62d6ec972$__63e4ee4bf78b8d8b8d8c8960c00151886040518863ffffffff1660e01b815260040161285e97969594939291906144d8565b60006040518083038186803b15801561287657600080fd5b505af415801561288a573d6000803e3d6000fd5b50505050600073__$8f1afe7577f9ab973017c74eca19b86f3c$__63ac2a37d685602001518c876060015188608001518960c001516040518663ffffffff1660e01b81526004016128df95949392919061455e565b600060405180830381865af41580156128fc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526129249190810190614592565b9550905080156129a8576040516326eadaa360e01b8152600481018e90526001600160a01b03891660248201526044810182905273__$8f1afe7577f9ab973017c74eca19b86f3c$__906326eadaa39060640160006040518083038186803b15801561298f57600080fd5b505af41580156129a3573d6000803e3d6000fd5b505050505b60408051828152602081018b905260008183015290517f83387a3342ff1ebc5e437dc9ae0f98274afda12a11cf547eebec05a3e0b8f8a79181900360600190a1505b50505098975050505050505050565b6002810154604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015612a45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612a6d91908101906145d8565b8260030160009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015612ac2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612aea91908101906145d8565b83546040805163ddca3f4360e01b81529051612b62926001600160a01b03169163ddca3f439160048083019260209291908290030181865afa158015612b34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b589190613fad565b62ffffff16613194565b604051602001612b749392919061464e565b6040516020818303038152906040529050919050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf19190613ed5565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015612c57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c7b9190613e52565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190613fe8565b60ff169050816000612cf483600a6147a3565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b602082015290915081612d3c5760405162461bcd60e51b81526004016107ac9190613e07565b5060008073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__6317c22c3c8e8e8e88886040518663ffffffff1660e01b8152600401612d7f959493929190614071565b606060405180830381865af4158015612d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc091906140a5565b509150915089612e0957612ddc82670de0b6b3a7640000613e94565b8387612df084670de0b6b3a7640000613e94565b612dfa9190613e94565b612e049190613ec1565b612e43565b8286612e1d83670de0b6b3a7640000613e94565b612e279190613e94565b612e319190613ec1565b612e4383670de0b6b3a7640000613e94565b985098505050505050505094509492505050565b6000816001600160a01b031663f77c47916040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebb9190613ed5565b6001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106eb9190613ed5565b6000806000612f2a87613294565b9050612f3881878787613305565b925092505094509492505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612f989084906133cf565b505050565b81546001600160a01b0316604080860191909152805160608101909152600583018054829060ff166003811115612fd657612fd661445e565b6003811115612fe757612fe761445e565b815260408051608081019182905260209092019190600184019060049082845b81548152602001906001019080831161300757505050918352505060408051608081019182905260209092019190600584019060049082845b815481526020019060010190808311613040575050509190925250505084526001600160a01b03838116602080870191909152600284015482166060870181905260038501549283166080880152600160a01b90920460ff16151560a0870152600091825282905260409020546130b6906134a1565b60c08501515260808401516001600160a01b03166000908152602082905260409020546130e2906134a1565b60c08501516001602002018181525050600084606001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315a9190613fe8565b60ff1690506012811061316e576001613184565b6131798160126147af565b61318490600a6147a3565b6101409095019490945250505050565b6060816000036131bb5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156131e557806131cf81613f08565b91506131de9050600a83613ec1565b91506131bf565b6000816001600160401b038111156131ff576131ff6137b1565b6040519080825280601f01601f191660200182016040528015613229576020820181803683370190505b5090505b8415610aab5761323e6001836147af565b915061324b600a866147c2565b613256906030613e81565b60f81b81838151811061326b5761326b613ef2565b60200101906001600160f81b031916908160001a90535061328d600a86613ec1565b945061322d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa1580156132d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f89190614105565b5093979650505050505050565b6000808061331386866147d6565b905060008460020b8260020b146133345761332f60028361433b565b613337565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063cd8e20e7906064016040805180830381865af415801561339c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c09190614395565b93509350505094509492505050565b6000613424826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134b99092919063ffffffff16565b805190915015612f9857808060200190518101906134429190614441565b612f985760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107ac565b600081156134af57816106eb565b620186a092915050565b6060610aab848460008585600080866001600160a01b031685876040516134e091906147fb565b60006040518083038185875af1925050503d806000811461351d576040519150601f19603f3d011682016040523d82523d6000602084013e613522565b606091505b50915091506135338783838761353e565b979650505050505050565b606083156135ad5782516000036135a6576001600160a01b0385163b6135a65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107ac565b5081610aab565b610aab83838151156135c25781518083602001fd5b8060405162461bcd60e51b81526004016107ac9190613e07565b60405180608001604052806004906020820280368337509192915050565b60405180610160016040528061360e613660565b815260006020820181905260408201819052606082018190526080820181905260a082015260c00161363e61368d565b8152600060208201819052604082018190526060820181905260809091015290565b6040805160608101909152806000815260200161367b6135dc565b81526020016136886135dc565b905290565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b03811681146136c057600080fd5b50565b8060020b81146136c057600080fd5b80151581146136c057600080fd5b600080600080608085870312156136f657600080fd5b8435613701816136ab565b93506020850135613711816136c3565b92506040850135613721816136c3565b91506060850135613731816136d2565b939692955090935050565b60006020828403121561374e57600080fd5b5035919050565b6000806040838503121561376857600080fd5b82359150602083013561377a816136ab565b809150509250929050565b60008060006060848603121561379a57600080fd5b505081359360208301359350604090920135919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156137ef576137ef6137b1565b604052919050565b60006001600160401b03821115613810576138106137b1565b5060051b60200190565b600082601f83011261382b57600080fd5b8135602061384061383b836137f7565b6137c7565b82815260059290921b8401810191818101908684111561385f57600080fd5b8286015b8481101561387a5780358352918301918301613863565b509695505050505050565b6000806000806080858703121561389b57600080fd5b84356138a6816136ab565b93506020858101356138b7816136ab565b935060408601356001600160401b03808211156138d357600080fd5b818801915088601f8301126138e757600080fd5b81356138f561383b826137f7565b81815260059190911b8301840190848101908b83111561391457600080fd5b938501935b8285101561393b57843561392c816136ab565b82529385019390850190613919565b96505050606088013592508083111561395357600080fd5b50506139618782880161381a565b91505092959194509250565b6001600160801b03811681146136c057600080fd5b6000806040838503121561399557600080fd5b82359150602083013561377a8161396d565b600081518084526020808501945080840160005b838110156139d7578151875295820195908201906001016139bb565b509495945050505050565b6020815260006139f560208301846139a7565b9392505050565b600060208284031215613a0e57600080fd5b81356139f5816136ab565b60008060008060008060c08789031215613a3257600080fd5b8635613a3d816136ab565b95506020870135613a4d816136c3565b94506040870135613a5d816136c3565b935060608701356001600160401b03811115613a7857600080fd5b613a8489828a0161381a565b9350506080870135613a958161396d565b915060a0870135613aa5816136d2565b809150509295509295509295565b606081526000613ac660608301866139a7565b90508360208301526001600160801b0383166040830152949350505050565b80608081018310156106eb57600080fd5b60006001600160401b03821115613b0f57613b0f6137b1565b50601f01601f191660200190565b600082601f830112613b2e57600080fd5b8135613b3c61383b82613af6565b818152846020838601011115613b5157600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060006101c0888a031215613b8a57600080fd5b8735965060c0880189811115613b9f57600080fd5b602089019650613baf8a82613ae5565b9550506101408801356001600160401b0380821115613bcd57600080fd5b613bd98b838c01613b1d565b95506101608a0135915080821115613bf057600080fd5b50613bfd8a828b01613b1d565b93505061018088013591506101a0880135905092959891949750929550565b8215158152604060208201526000610aab60408301846139a7565b6000806000806000806000610140888a031215613c5357600080fd5b873596506020880135613c65816136ab565b95506040880135613c75816136ab565b94506060880135613c85816136c3565b93506080880135613c95816136c3565b925060a0880135613ca5816136ab565b9150613cb48960c08a01613ae5565b905092959891949750929550565b606080825284519082018190526000906020906080840190828801845b82811015613d045781516001600160a01b031684529284019290840190600101613cdf565b50505083810382850152613d1881876139a7565b9150508281036040840152613d2d81856139a7565b9695505050505050565b600080600080600080600080610120898b031215613d5457600080fd5b8835975060208901359650608089018a811115613d7057600080fd5b60408a01965035945060a0890135935060c0890135613d8e816136ab565b925060e0890135613d9e816136d2565b8092505061010089013590509295985092959890939650565b60005b83811015613dd2578181015183820152602001613dba565b50506000910152565b60008151808452613df3816020860160208601613db7565b601f01601f19169290920160200192915050565b6020815260006139f56020830184613ddb565b60008060408385031215613e2d57600080fd5b505080516020909101519092909150565b6001600160a01b0391909116815260200190565b600060208284031215613e6457600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156106eb576106eb613e6b565b80820281158282048414176106eb576106eb613e6b565b634e487b7160e01b600052601260045260246000fd5b600082613ed057613ed0613eab565b500490565b600060208284031215613ee757600080fd5b81516139f5816136ab565b634e487b7160e01b600052603260045260246000fd5b600060018201613f1a57613f1a613e6b565b5060010190565b6001600160a01b03959095168552600293840b60208601529190920b60408401526001600160801b03918216606084015216608082015260a00190565b60008060408385031215613f7157600080fd5b8251613f7c8161396d565b602084015190925061377a8161396d565b6001600160801b038281168282160390808211156119c8576119c8613e6b565b600060208284031215613fbf57600080fd5b815162ffffff811681146139f557600080fd5b805160ff81168114613fe357600080fd5b919050565b600060208284031215613ffa57600080fd5b6139f582613fd2565b60006020828403121561401557600080fd5b81516139f5816136c3565b60008060006060848603121561403557600080fd5b8351614040816136d2565b6020850151909350614051816136d2565b60408501519092506004811061406657600080fd5b809150509250925092565b6001600160a01b03959095168552600293840b60208601529190920b60408401526060830191909152608082015260a00190565b6000806000606084860312156140ba57600080fd5b835192506020840151915060408401516140668161396d565b6001600160801b038181168382160190808211156119c8576119c8613e6b565b805161ffff81168114613fe357600080fd5b600080600080600080600060e0888a03121561412057600080fd5b875161412b816136ab565b602089015190975061413c816136c3565b955061414a604089016140f3565b9450614158606089016140f3565b9350614166608089016140f3565b925061417460a08901613fd2565b915060c0880151614184816136d2565b8091505092959891949750929550565b6001600160a01b03949094168452600292830b6020850152910b60408301526001600160801b0316606082015260800190565b60808183375050565b60006101c08289835b600581101561420b5781356141ed816136ab565b6001600160a01b0316835260209283019291909101906001016141d9565b50505060808860a08501378061012084015261422981840188613ddb565b905082810361014084015261423e8187613ddb565b91505061016082018460005b60028110156142725781516001600160a01b031683526020928301929091019060010161424a565b505050826101a0830152979650505050505050565b600082601f83011261429857600080fd5b815160206142a861383b836137f7565b82815260059290921b840181019181810190868411156142c757600080fd5b8286015b8481101561387a57805183529183019183016142cb565b6000806000606084860312156142f757600080fd5b8351614302816136d2565b60208501519093506001600160401b0381111561431e57600080fd5b61432a86828701614287565b925050604084015190509250925092565b60008160020b8360020b8061435257614352613eab565b627fffff1982146000198214161561436c5761436c613e6b565b90059392505050565b60008260020b8260020b028060020b91508082146119c8576119c8613e6b565b600080604083850312156143a857600080fd5b82516143b3816136c3565b602084015190925061377a816136c3565b8581526101c0810160208083018760005b60048110156143fb5781516001600160a01b0316835291830191908301906001016143d5565b50505060a083018660005b600481101561442657815160020b83529183019190830190600101614406565b50505050831515610120830152613d2d6101408301846141c7565b60006020828403121561445357600080fd5b81516139f5816136d2565b634e487b7160e01b600052602160045260246000fd5b838152821515602082015260608101600483106144a157634e487b7160e01b600052602160045260246000fd5b826040830152949350505050565b8060005b60028110156144d25781518452602093840193909101906001016144b3565b50505050565b6101208101818960005b60028110156145145781356144f6816136ab565b6001600160a01b0316835260209283019291909101906001016144e2565b5050506040820188905260608201879052608082018690526001600160a01b03851660a083015261454860c08301856144af565b8260020b61010083015298975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260c08101613d2d60808301846144af565b600080604083850312156145a557600080fd5b8251915060208301516001600160401b038111156145c257600080fd5b6145ce85828601614287565b9150509250929050565b6000602082840312156145ea57600080fd5b81516001600160401b0381111561460057600080fd5b8201601f8101841361461157600080fd5b805161461f61383b82613af6565b81815285602083850101111561463457600080fd5b614645826020830160208601613db7565b95945050505050565b6502ab734ab19960d51b81526000845161466f816006850160208901613db7565b602f60f81b6006918401918201528451614690816007840160208901613db7565b602d60f81b6007929091019182015283516146b2816008840160208801613db7565b0160080195945050505050565b600181815b808511156146fa5781600019048211156146e0576146e0613e6b565b808516156146ed57918102915b93841c93908002906146c4565b509250929050565b600082614711575060016106eb565b8161471e575060006106eb565b8160018114614734576002811461473e5761475a565b60019150506106eb565b60ff84111561474f5761474f613e6b565b50506001821b6106eb565b5060208310610133831016604e8410600b841016171561477d575081810a6106eb565b61478783836146bf565b806000190482111561479b5761479b613e6b565b029392505050565b60006139f58383614702565b818103818111156106eb576106eb613e6b565b6000826147d1576147d1613eab565b500690565b600282810b9082900b03627fffff198112627fffff821317156106eb576106eb613e6b565b6000825161480d818460208701613db7565b919091019291505056fe5533532d3133205a65726f2073747261746567792070726f66697420686f6c6465725042532d3420496e636f727265637420726562616c616e63655469636b52616e6765a264697066735822122083da58e5269555d01b1905b58be1c345b274f3f88d5186dbbc1e8db6862e15f864736f6c63430008110033", "libraries": { "UniswapV3Lib": "0xD398438a52fD230195861b9Af0B4Ab8e9b0006F2", - "PairBasedStrategyLogicLib": "0xB2dD88095aFe40481C4969f8761DE3D6BC08D222", - "UniswapV3DebtLib": "0x536d15b1F898f8648Cb3633F4531B133A69c7e90", + "PairBasedStrategyLogicLib": "0x06901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39", + "UniswapV3DebtLib": "0xBC79449e023737acFF022427C51e74F932B7F88A", "ConverterStrategyBaseLib2": "0xC92346a144fa75b45b0eDAe966FEAA0E30C82c55", - "PairBasedStrategyLib": "0xE5779B35180c1048562c733A7E62f8Fe1d253C41" + "PairBasedStrategyLib": "0xE0D8b85C7Feb11b26e5A2466931088eC5DE7A703" }, "devdoc": { "kind": "dev", diff --git a/deployments/matic/UniswapV3DebtLib.json b/deployments/matic/UniswapV3DebtLib.json index 4b6b9c47..76e03cd8 100644 --- a/deployments/matic/UniswapV3DebtLib.json +++ b/deployments/matic/UniswapV3DebtLib.json @@ -1,5 +1,5 @@ { - "address": "0x536d15b1F898f8648Cb3633F4531B133A69c7e90", + "address": "0xBC79449e023737acFF022427C51e74F932B7F88A", "abi": [ { "inputs": [], @@ -68,49 +68,49 @@ "type": "function" } ], - "transactionHash": "0x7e7f75d635eea52a4db1eed7b8d6f7d37d90ddee85330efaca4b03d801bb00dd", + "transactionHash": "0x12a140790161e8d9085dc34bdbab52ae9dcdf3d419b36d9b7fe160534af5890b", "receipt": { "to": null, "from": "0xF1dCce3a6c321176C62b71c091E3165CC9C3816E", - "contractAddress": "0x536d15b1F898f8648Cb3633F4531B133A69c7e90", - "transactionIndex": 114, - "gasUsed": "810395", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000004000000000000000000000000000000000000800000000000000000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000100000000000000000000000000000000000000000000000000000200080000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", - "blockHash": "0x6ae9072a0e32202bce0e2ce28c777c4e6057817611da6f99c4227e21d7643ee3", - "transactionHash": "0x7e7f75d635eea52a4db1eed7b8d6f7d37d90ddee85330efaca4b03d801bb00dd", + "contractAddress": "0xBC79449e023737acFF022427C51e74F932B7F88A", + "transactionIndex": 38, + "gasUsed": "810407", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000400000000100000000000000000000000000040000000000000000000000000000000080000000004000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000100000", + "blockHash": "0x9f468d20a0bc767b3c3513c3eece97fe6f79f053ebf38380961ab7e34fad765f", + "transactionHash": "0x12a140790161e8d9085dc34bdbab52ae9dcdf3d419b36d9b7fe160534af5890b", "logs": [ { - "transactionIndex": 114, - "blockNumber": 54803455, - "transactionHash": "0x7e7f75d635eea52a4db1eed7b8d6f7d37d90ddee85330efaca4b03d801bb00dd", + "transactionIndex": 38, + "blockNumber": 55572334, + "transactionHash": "0x12a140790161e8d9085dc34bdbab52ae9dcdf3d419b36d9b7fe160534af5890b", "address": "0x0000000000000000000000000000000000001010", "topics": [ "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", "0x0000000000000000000000000000000000000000000000000000000000001010", "0x000000000000000000000000f1dcce3a6c321176c62b71c091e3165cc9c3816e", - "0x000000000000000000000000048cfedf907c4c9ddd11ff882380906e78e84bbe" + "0x0000000000000000000000007c7379531b2aee82e4ca06d4175d13b9cbeafd49" ], - "data": "0x000000000000000000000000000000000000000000000000000451932f27750000000000000000000000000000000000000000000000000266d9db1933c2c786000000000000000000000000000000000000000000002436cd0be2da4fcc96b400000000000000000000000000000000000000000000000266d58986049b5286000000000000000000000000000000000000000000002436cd10346d7ef40bb4", - "logIndex": 417, - "blockHash": "0x6ae9072a0e32202bce0e2ce28c777c4e6057817611da6f99c4227e21d7643ee3" + "data": "0x00000000000000000000000000000000000000000000000000a36b2c628f07dc000000000000000000000000000000000000000000000001d563ece52725c25c00000000000000000000000000000000000000000002e458aa0471136d748afe000000000000000000000000000000000000000000000001d4c081b8c496ba8000000000000000000000000000000000000000000002e458aaa7dc3fd00392da", + "logIndex": 165, + "blockHash": "0x9f468d20a0bc767b3c3513c3eece97fe6f79f053ebf38380961ab7e34fad765f" } ], - "blockNumber": 54803455, - "cumulativeGasUsed": "18063135", + "blockNumber": 55572334, + "cumulativeGasUsed": "5901867", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 32, - "solcInputHash": "a408f1fd06b60723e7f996d4b67ed7ec", - "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"SELL_GAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickRange\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"calcTickRange\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"}],\"name\":\"getCurrentTick\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"rebalanceNoSwaps(address[2],PairBasedStrategyLogicLib.PairState storage,uint256,uint256,address,uint256[2],int24)\":{\"params\":{\"liquidationThresholdsAB\":\"[liquidityThreshold of token A, liquidityThreshold of tokenB]\",\"tick\":\"Current tick in the pool\"}}},\"stateVariables\":{\"BORROW_PERIOD_ESTIMATION\":{\"details\":\"should be placed local, probably will be adjusted later\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"rebalanceNoSwaps(address[2],PairBasedStrategyLogicLib.PairState storage,uint256,uint256,address,uint256[2],int24)\":{\"notice\":\"Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":\"UniswapV3DebtLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct SwapToGetAmountLocal {\\r\\n uint len;\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConvertAfterWithdrawLocal {\\r\\n address asset;\\r\\n uint spent;\\r\\n uint received;\\r\\n uint balance;\\r\\n uint balanceBefore;\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountInputParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n uint targetAmount;\\r\\n address[] tokens;\\r\\n uint[] amounts;\\r\\n /// @notice liquidationThresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n uint indexTargetAsset;\\r\\n address underlying;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%)\\r\\n /// to avoid additional swap if the swap return amount a bit less than we expected\\r\\n uint overswap;\\r\\n }\\r\\n\\r\\n struct SwapToGivenAmountLocal {\\r\\n uint len;\\r\\n uint[] availableAmounts;\\r\\n uint i;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n uint compoundRatio;\\r\\n uint performanceFee;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint[] amountsToForward;\\r\\n uint[] thresholds;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n address splitter;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address splitter;\\r\\n\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.compoundRatio = baseState.compoundRatio;\\r\\n v.performanceFee = baseState.performanceFee;\\r\\n v.thresholds = _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length);\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n v.splitter = baseState.splitter;\\r\\n\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: v.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: v.thresholds,\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFee,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n splitter: v.splitter,\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n }));\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.splitter,\\r\\n baseState.performanceReceiver,\\r\\n baseState.performanceFeeRatio\\r\\n );\\r\\n\\r\\n // override rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.splitter, rewardTokens_, v.amountsToForward, v.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset_ Underlying asset\\r\\n /// @param amount_ Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver_ Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n function _sendPerformanceFee(address asset_, uint amount_, address splitter, address receiver_, uint ratio) internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n // read inside lib for reduce contract space in the main contract\\r\\n address insurance = address(ITetuVaultV2(ISplitter(splitter).vault()).insurance());\\r\\n\\r\\n toPerf = amount_ * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount_ - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n IERC20(asset_).safeTransfer(receiver_, toPerf);\\r\\n }\\r\\n if (toInsurance != 0) {\\r\\n IERC20(asset_).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address splitter_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, ISplitter(splitter_).vault(), true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn;\\r\\n\\r\\n if (amountAsset > debtAmount + p.assetThreshold) {\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n amountIn = p.rewardAmounts[index] * debtAmount / amountAsset;\\r\\n } else {\\r\\n // pay all available rewards to cover a part of the debt\\r\\n amountIn = p.rewardAmounts[index];\\r\\n }\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(address(ITetuVaultV2(ISplitter(p.splitter).vault()).insurance()), amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x8dd1596a48aeabdaef121d613050c7731576aece3782a3c3042b33be3be7a13e\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", - "bytecode": "0x610db261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806317b13c951461005b5780636c55a3ca14610086578063e4ee4bf7146100b3578063f8328d9f146100d5575b600080fd5b61006e6100693660046108c7565b6100eb565b60405160029190910b81526020015b60405180910390f35b6100996100943660046108fa565b61015c565b60408051600293840b81529190920b60208201520161007d565b8180156100bf57600080fd5b506100d36100ce36600461095c565b610200565b005b6100dd606481565b60405190815260200161007d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014f91906109ff565b5093979650505050505050565b60008073B2dD88095aFe40481C4969f8761DE3D6BC08D22263cd8e20e7610182876100eb565b6040516001600160e01b031960e084901b168152600291820b600482015287820b60248201529086900b60448201526064016040805180830381865af41580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610a83565b91509150935093915050565b60038601546000908190610236908490600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b6102ed565b895460038b0154929450909250600091829161026b916001600160a01b039091169086908690600160a81b900460ff166103b7565b90925090506102a48b8b8b8b8b8b610283888a610ad3565b610295670de0b6b3a76400008b610ae6565b61029f9190610b13565b6106ab565b5050600397909701805465ffffffffffff60c81b1916600160e01b62ffffff998a160262ffffff60c81b191617600160c81b929098169190910296909617909555505050505050565b600080806102fb8686610b27565b905060008460020b8260020b1461031c57610317600283610b4c565b61031f565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073B2dD88095aFe40481C4969f8761DE3D6BC08D2229063cd8e20e7906064016040805180830381865af4158015610384573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a89190610a83565b93509350505094509492505050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041e9190610b86565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015610484573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a89190610ba3565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190610bbc565b60ff16905081600061052183600a610cbb565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152909150816105725760405162461bcd60e51b81526004016105699190610cc7565b60405180910390fd5b506040516305f08b0f60e21b81526001600160a01b038c16600482015260028b810b60248301528a900b60448201526064810183905260848101829052600090819073D398438a52fD230195861b9Af0B4Ab8e9b0006F2906317c22c3c9060a401606060405180830381865af41580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106149190610d15565b50915091508961065d5761063082670de0b6b3a7640000610ae6565b838761064484670de0b6b3a7640000610ae6565b61064e9190610ae6565b6106589190610b13565b610697565b828661067183670de0b6b3a7640000610ae6565b61067b9190610ae6565b6106859190610b13565b61069783670de0b6b3a7640000610ae6565b985098505050505050505094509492505050565b600286015460038701546001600160a01b03918216911673d84c6293b2E190DDd7Ea7F6E00396A840294BDcE6343f8b62c6106e960208c018c6108c7565b6106f960408d0160208e016108c7565b60405160e084901b6001600160e01b03191681526001600160a01b03928316600482015290821660248201528186166044820152908416606482015260848101869052863560a4820152602087013560c482015260e481018a90526101040160006040518083038186803b15801561077057600080fd5b505af4158015610784573d6000803e3d6000fd5b50505050866000146108a4576040516370a0823160e01b815230600482015273C92346a144fa75b45b0eDAe966FEAA0E30C82c559063890ffb849084908a9089908b906001600160a01b038516906370a0823190602401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610ba3565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af415801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190610d58565b50505b505050505050505050565b6001600160a01b03811681146108c457600080fd5b50565b6000602082840312156108d957600080fd5b81356108e4816108af565b9392505050565b8060020b81146108c457600080fd5b60008060006060848603121561090f57600080fd5b833561091a816108af565b9250602084013561092a816108eb565b9150604084013561093a816108eb565b809150509250925092565b806040810183101561095657600080fd5b92915050565b6000806000806000806000610120888a03121561097857600080fd5b6109828989610945565b965060408801359550606088013594506080880135935060a08801356109a7816108af565b92506109b68960c08a01610945565b91506101008801356109c7816108eb565b8091505092959891949750929550565b805161ffff811681146109e957600080fd5b919050565b805160ff811681146109e957600080fd5b600080600080600080600060e0888a031215610a1a57600080fd5b8751610a25816108af565b6020890151909750610a36816108eb565b9550610a44604089016109d7565b9450610a52606089016109d7565b9350610a60608089016109d7565b9250610a6e60a089016109ee565b915060c088015180151581146109c757600080fd5b60008060408385031215610a9657600080fd5b8251610aa1816108eb565b6020840151909250610ab2816108eb565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561095657610956610abd565b808202811582820484141761095657610956610abd565b634e487b7160e01b600052601260045260246000fd5b600082610b2257610b22610afd565b500490565b600282810b9082900b03627fffff198112627fffff8213171561095657610956610abd565b60008160020b8360020b80610b6357610b63610afd565b627fffff19821460001982141615610b7d57610b7d610abd565b90059392505050565b600060208284031215610b9857600080fd5b81516108e4816108af565b600060208284031215610bb557600080fd5b5051919050565b600060208284031215610bce57600080fd5b6108e4826109ee565b600181815b80851115610c12578160001904821115610bf857610bf8610abd565b80851615610c0557918102915b93841c9390800290610bdc565b509250929050565b600082610c2957506001610956565b81610c3657506000610956565b8160018114610c4c5760028114610c5657610c72565b6001915050610956565b60ff841115610c6757610c67610abd565b50506001821b610956565b5060208310610133831016604e8410600b8410161715610c95575081810a610956565b610c9f8383610bd7565b8060001904821115610cb357610cb3610abd565b029392505050565b60006108e48383610c1a565b600060208083528351808285015260005b81811015610cf457858101830151858201604001528201610cd8565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600060608486031215610d2a57600080fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff8116811461093a57600080fd5b60008060408385031215610d6b57600080fd5b50508051602090910151909290915056fea2646970667358221220b0a431557eb27fd6d941ac3ac5610bbfaab0e1370534caff8f7f4e4ca5c78f5964736f6c63430008110033", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806317b13c951461005b5780636c55a3ca14610086578063e4ee4bf7146100b3578063f8328d9f146100d5575b600080fd5b61006e6100693660046108c7565b6100eb565b60405160029190910b81526020015b60405180910390f35b6100996100943660046108fa565b61015c565b60408051600293840b81529190920b60208201520161007d565b8180156100bf57600080fd5b506100d36100ce36600461095c565b610200565b005b6100dd606481565b60405190815260200161007d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014f91906109ff565b5093979650505050505050565b60008073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__63cd8e20e7610182876100eb565b6040516001600160e01b031960e084901b168152600291820b600482015287820b60248201529086900b60448201526064016040805180830381865af41580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610a83565b91509150935093915050565b60038601546000908190610236908490600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b6102ed565b895460038b0154929450909250600091829161026b916001600160a01b039091169086908690600160a81b900460ff166103b7565b90925090506102a48b8b8b8b8b8b610283888a610ad3565b610295670de0b6b3a76400008b610ae6565b61029f9190610b13565b6106ab565b5050600397909701805465ffffffffffff60c81b1916600160e01b62ffffff998a160262ffffff60c81b191617600160c81b929098169190910296909617909555505050505050565b600080806102fb8686610b27565b905060008460020b8260020b1461031c57610317600283610b4c565b61031f565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063cd8e20e7906064016040805180830381865af4158015610384573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a89190610a83565b93509350505094509492505050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041e9190610b86565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015610484573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a89190610ba3565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190610bbc565b60ff16905081600061052183600a610cbb565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152909150816105725760405162461bcd60e51b81526004016105699190610cc7565b60405180910390fd5b506040516305f08b0f60e21b81526001600160a01b038c16600482015260028b810b60248301528a900b60448201526064810183905260848101829052600090819073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__906317c22c3c9060a401606060405180830381865af41580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106149190610d15565b50915091508961065d5761063082670de0b6b3a7640000610ae6565b838761064484670de0b6b3a7640000610ae6565b61064e9190610ae6565b6106589190610b13565b610697565b828661067183670de0b6b3a7640000610ae6565b61067b9190610ae6565b6106859190610b13565b61069783670de0b6b3a7640000610ae6565b985098505050505050505094509492505050565b600286015460038701546001600160a01b03918216911673__$295fb458e6648e6381ea46363bb426e5e7$__6343f8b62c6106e960208c018c6108c7565b6106f960408d0160208e016108c7565b60405160e084901b6001600160e01b03191681526001600160a01b03928316600482015290821660248201528186166044820152908416606482015260848101869052863560a4820152602087013560c482015260e481018a90526101040160006040518083038186803b15801561077057600080fd5b505af4158015610784573d6000803e3d6000fd5b50505050866000146108a4576040516370a0823160e01b815230600482015273__$8f1afe7577f9ab973017c74eca19b86f3c$__9063890ffb849084908a9089908b906001600160a01b038516906370a0823190602401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610ba3565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af415801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190610d58565b50505b505050505050505050565b6001600160a01b03811681146108c457600080fd5b50565b6000602082840312156108d957600080fd5b81356108e4816108af565b9392505050565b8060020b81146108c457600080fd5b60008060006060848603121561090f57600080fd5b833561091a816108af565b9250602084013561092a816108eb565b9150604084013561093a816108eb565b809150509250925092565b806040810183101561095657600080fd5b92915050565b6000806000806000806000610120888a03121561097857600080fd5b6109828989610945565b965060408801359550606088013594506080880135935060a08801356109a7816108af565b92506109b68960c08a01610945565b91506101008801356109c7816108eb565b8091505092959891949750929550565b805161ffff811681146109e957600080fd5b919050565b805160ff811681146109e957600080fd5b600080600080600080600060e0888a031215610a1a57600080fd5b8751610a25816108af565b6020890151909750610a36816108eb565b9550610a44604089016109d7565b9450610a52606089016109d7565b9350610a60608089016109d7565b9250610a6e60a089016109ee565b915060c088015180151581146109c757600080fd5b60008060408385031215610a9657600080fd5b8251610aa1816108eb565b6020840151909250610ab2816108eb565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561095657610956610abd565b808202811582820484141761095657610956610abd565b634e487b7160e01b600052601260045260246000fd5b600082610b2257610b22610afd565b500490565b600282810b9082900b03627fffff198112627fffff8213171561095657610956610abd565b60008160020b8360020b80610b6357610b63610afd565b627fffff19821460001982141615610b7d57610b7d610abd565b90059392505050565b600060208284031215610b9857600080fd5b81516108e4816108af565b600060208284031215610bb557600080fd5b5051919050565b600060208284031215610bce57600080fd5b6108e4826109ee565b600181815b80851115610c12578160001904821115610bf857610bf8610abd565b80851615610c0557918102915b93841c9390800290610bdc565b509250929050565b600082610c2957506001610956565b81610c3657506000610956565b8160018114610c4c5760028114610c5657610c72565b6001915050610956565b60ff841115610c6757610c67610abd565b50506001821b610956565b5060208310610133831016604e8410600b8410161715610c95575081810a610956565b610c9f8383610bd7565b8060001904821115610cb357610cb3610abd565b029392505050565b60006108e48383610c1a565b600060208083528351808285015260005b81811015610cf457858101830151858201604001528201610cd8565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600060608486031215610d2a57600080fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff8116811461093a57600080fd5b60008060408385031215610d6b57600080fd5b50508051602090910151909290915056fea2646970667358221220b0a431557eb27fd6d941ac3ac5610bbfaab0e1370534caff8f7f4e4ca5c78f5964736f6c63430008110033", + "numDeployments": 33, + "solcInputHash": "feb9ce27aac3fb5d00c9064a99a34ff0", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"SELL_GAP\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickRange\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"calcTickRange\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"lowerTick\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"upperTick\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IUniswapV3Pool\",\"name\":\"pool\",\"type\":\"IUniswapV3Pool\"}],\"name\":\"getCurrentTick\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"rebalanceNoSwaps(address[2],PairBasedStrategyLogicLib.PairState storage,uint256,uint256,address,uint256[2],int24)\":{\"params\":{\"liquidationThresholdsAB\":\"[liquidityThreshold of token A, liquidityThreshold of tokenB]\",\"tick\":\"Current tick in the pool\"}}},\"stateVariables\":{\"BORROW_PERIOD_ESTIMATION\":{\"details\":\"should be placed local, probably will be adjusted later\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"rebalanceNoSwaps(address[2],PairBasedStrategyLogicLib.PairState storage,uint256,uint256,address,uint256[2],int24)\":{\"notice\":\"Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":\"UniswapV3DebtLib\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":150},\"remappings\":[]},\"sources\":{\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IControllable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IControllable {\\n\\n function isController(address _contract) external view returns (bool);\\n\\n function isGovernance(address _contract) external view returns (bool);\\n\\n function created() external view returns (uint256);\\n\\n function createdBlock() external view returns (uint256);\\n\\n function controller() external view returns (address);\\n\\n function increaseRevision(address oldLogic) external;\\n\\n}\\n\",\"keccak256\":\"0xc2ef11f0141e7e1a5df255be2e1552044deed377349cb886908f3f10ded57fa8\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IController {\\n\\n // --- DEPENDENCY ADDRESSES\\n function governance() external view returns (address);\\n\\n function voter() external view returns (address);\\n\\n function liquidator() external view returns (address);\\n\\n function forwarder() external view returns (address);\\n\\n function investFund() external view returns (address);\\n\\n function veDistributor() external view returns (address);\\n\\n function platformVoter() external view returns (address);\\n\\n // --- VAULTS\\n\\n function vaults(uint id) external view returns (address);\\n\\n function vaultsList() external view returns (address[] memory);\\n\\n function vaultsListLength() external view returns (uint);\\n\\n function isValidVault(address _vault) external view returns (bool);\\n\\n // --- restrictions\\n\\n function isOperator(address _adr) external view returns (bool);\\n\\n\\n}\\n\",\"keccak256\":\"0x86716b8a4775605c31b8bb9f90f8f4a18b709ff4435182f3a148803368060a8c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\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 (uint);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint);\\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, uint 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 (uint);\\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, uint 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(\\n address sender,\\n address recipient,\\n uint amount\\n ) 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, uint 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, uint value);\\n}\\n\",\"keccak256\":\"0x5f43ed533d0fc4dc2f8f081d2c4b77960f3e908d5f7359096b385e5673f1ba0c\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IERC20.sol\\\";\\n\\n/**\\n * https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/release-v4.6/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x953f20efa64081a325109a0e03602b889d2819c2b51c1e1fb21a062feeda74f3\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x9f69f84d864c2a84de9321871aa52f6f70d14afe46badbcd37c0d4f22af75e7b\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IForwarder {\\n\\n function tetu() external view returns (address);\\n function tetuThreshold() external view returns (uint);\\n\\n function tokenPerDestinationLength(address destination) external view returns (uint);\\n\\n function tokenPerDestinationAt(address destination, uint i) external view returns (address);\\n\\n function amountPerDestination(address token, address destination) external view returns (uint amount);\\n\\n function registerIncome(\\n address[] memory tokens,\\n uint[] memory amounts,\\n address vault,\\n bool isDistribute\\n ) external;\\n\\n function distributeAll(address destination) external;\\n\\n function distribute(address token) external;\\n\\n function setInvestFundRatio(uint value) external;\\n\\n function setGaugesRatio(uint value) external;\\n\\n}\\n\",\"keccak256\":\"0x687c497fc034e8d64bca403bac1bf4cd7bd1f107df414c2657325c1b3ab92822\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface ISplitter {\\n\\n function init(address controller_, address _asset, address _vault) external;\\n\\n // *************** ACTIONS **************\\n\\n function withdrawAllToVault() external;\\n\\n function withdrawToVault(uint256 amount) external;\\n\\n function coverPossibleStrategyLoss(uint earned, uint lost) external;\\n\\n function doHardWork() external;\\n\\n function investAll() external;\\n\\n // **************** VIEWS ***************\\n\\n function asset() external view returns (address);\\n\\n function vault() external view returns (address);\\n\\n function totalAssets() external view returns (uint256);\\n\\n function isHardWorking() external view returns (bool);\\n\\n function strategies(uint i) external view returns (address);\\n\\n function strategiesLength() external view returns (uint);\\n\\n function HARDWORK_DELAY() external view returns (uint);\\n\\n function lastHardWorks(address strategy) external view returns (uint);\\n\\n function pausedStrategies(address strategy) external view returns (bool);\\n\\n function pauseInvesting(address strategy) external;\\n\\n function continueInvesting(address strategy, uint apr) external;\\n\\n function rebalance(uint percent, uint lossTolerance) external;\\n\\n function getStrategyCapacity(address strategy) external view returns (uint capacity);\\n\\n}\\n\",\"keccak256\":\"0x266c43734e3da96d9e5dcdd0f19c6dbd58fdc377c9cd361cb12da3e309fbb4ec\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IStrategyV2 {\\n\\n function NAME() external view returns (string memory);\\n\\n function strategySpecificName() external view returns (string memory);\\n\\n function PLATFORM() external view returns (string memory);\\n\\n function STRATEGY_VERSION() external view returns (string memory);\\n\\n function asset() external view returns (address);\\n\\n function splitter() external view returns (address);\\n\\n function compoundRatio() external view returns (uint);\\n\\n function totalAssets() external view returns (uint);\\n\\n /// @dev Usually, indicate that claimable rewards have reasonable amount.\\n function isReadyToHardWork() external view returns (bool);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawAllToSplitter() external returns (uint strategyLoss);\\n\\n /// @return strategyLoss Loss should be covered from Insurance\\n function withdrawToSplitter(uint amount) external returns (uint strategyLoss);\\n\\n /// @notice Stakes everything the strategy holds into the reward pool.\\n /// @param amount_ Amount transferred to the strategy balance just before calling this function\\n /// @param updateTotalAssetsBeforeInvest_ Recalculate total assets amount before depositing.\\n /// It can be false if we know exactly, that the amount is already actual.\\n /// @return strategyLoss Loss should be covered from Insurance\\n function investAll(\\n uint amount_,\\n bool updateTotalAssetsBeforeInvest_\\n ) external returns (\\n uint strategyLoss\\n );\\n\\n function doHardWork() external returns (uint earned, uint lost);\\n\\n function setCompoundRatio(uint value) external;\\n\\n /// @notice Max amount that can be deposited to the strategy (its internal capacity), see SCB-593.\\n /// 0 means no deposit is allowed at this moment\\n function capacity() external view returns (uint);\\n\\n /// @notice {performanceFee}% of total profit is sent to the {performanceReceiver} before compounding\\n function performanceReceiver() external view returns (address);\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev use FEE_DENOMINATOR\\n function performanceFee() external view returns (uint);\\n}\\n\",\"keccak256\":\"0xc7dac6097df7310b510f1027ef9c1bd3ccd6a202ca69582f68233ee798f7c312\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\nimport \\\"./IStrategyV2.sol\\\";\\n\\ninterface IStrategyV3 is IStrategyV2 {\\n struct BaseState {\\n /// @dev Underlying asset\\n address asset;\\n\\n /// @dev Linked splitter\\n address splitter;\\n\\n /// @notice {performanceFee}% of total profit is sent to {performanceReceiver} before compounding\\n /// @dev governance by default\\n address performanceReceiver;\\n\\n /// @notice A percent of total profit that is sent to the {performanceReceiver} before compounding\\n /// @dev {DEFAULT_PERFORMANCE_FEE} by default, FEE_DENOMINATOR is used\\n uint performanceFee;\\n\\n /// @notice Ratio to split performance fee on toPerf + toInsurance, [0..100_000]\\n /// 100_000 - send full amount toPerf, 0 - send full amount toInsurance.\\n uint performanceFeeRatio;\\n\\n /// @dev Percent of profit for autocompound inside this strategy.\\n uint compoundRatio;\\n\\n /// @dev Represent specific name for this strategy. Should include short strategy name and used assets. Uniq across the vault.\\n string strategySpecificName;\\n }\\n}\\n\",\"keccak256\":\"0xe8a0179a82c40ba0c372486c5ebcc7df6431216c8c0d91cc408fb8f881e72f70\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface ITetuLiquidator {\\n\\n struct PoolData {\\n address pool;\\n address swapper;\\n address tokenIn;\\n address tokenOut;\\n }\\n\\n function addLargestPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function addBlueChipsPools(PoolData[] memory _pools, bool rewrite) external;\\n\\n function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint);\\n\\n function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint);\\n\\n function isRouteExist(address tokenIn, address tokenOut) external view returns (bool);\\n\\n function buildRoute(\\n address tokenIn,\\n address tokenOut\\n ) external view returns (PoolData[] memory route, string memory errorMessage);\\n\\n function liquidate(\\n address tokenIn,\\n address tokenOut,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n function liquidateWithRoute(\\n PoolData[] memory route,\\n uint amount,\\n uint slippage\\n ) external;\\n\\n\\n}\\n\",\"keccak256\":\"0xd5fe6f3ab750cc2d23f573597db5607c701e74c39e13c20c07a921a26c6d5012\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IVaultInsurance.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./ISplitter.sol\\\";\\n\\ninterface ITetuVaultV2 {\\n\\n function splitter() external view returns (ISplitter);\\n\\n function insurance() external view returns (IVaultInsurance);\\n\\n function depositFee() external view returns (uint);\\n\\n function withdrawFee() external view returns (uint);\\n\\n function init(\\n address controller_,\\n IERC20 _asset,\\n string memory _name,\\n string memory _symbol,\\n address _gauge,\\n uint _buffer\\n ) external;\\n\\n function setSplitter(address _splitter) external;\\n\\n function coverLoss(uint amount) external;\\n\\n function initInsurance(IVaultInsurance _insurance) external;\\n\\n}\\n\",\"keccak256\":\"0x9e77a10b32a52f826d28d17c420f776fd289e5e4f925ec87f7177a1ce224a412\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IVaultInsurance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IVaultInsurance {\\n\\n function init(address _vault, address _asset) external;\\n\\n function vault() external view returns (address);\\n\\n function asset() external view returns (address);\\n\\n function transferToVault(uint amount) external;\\n\\n}\\n\",\"keccak256\":\"0x6461572763b1f6decec1dee9d2ffe8ca152369bdc68255ec083cb3da3ce507a1\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity 0.8.17;\\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 * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/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 (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 functionCallWithValue(target, data, 0, \\\"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(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) 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(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\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 /// @solidity memory-safe-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\",\"keccak256\":\"0xcc7eeaafd4384e04ff39e0c01f0a6794736c34cad529751b8abd7b088ecc2e83\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity 0.8.17;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\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.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1, \\\"Math: mulDiv overflow\\\");\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2c5be0f4a60126b08e20f40586958ec1b76a27b69406c4b0db19e9dc6f771cfc\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../interfaces/IERC20.sol\\\";\\nimport \\\"../interfaces/IERC20Permit.sol\\\";\\nimport \\\"./Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) 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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) 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 require(\\n (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(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\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) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2378ee07b24e40c75781b27b2aa0812769c0000964e2d2501e3d234d3285dd18\",\"license\":\"MIT\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\n\\nlibrary StrategyLib {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkCompoundRatioChanged(address controller, uint oldValue, uint newValue) external {\\n onlyPlatformVoter(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _checkStrategySpecificNameChanged(address controller, string calldata newName) external {\\n onlyOperators(controller);\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoter(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_) external view {\\n onlyGovernance(controller);\\n require(fee_ <= 100_000, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0xa89e85b9acaeb5238c11c864167c152d0c33cf800fa3bb447e0629ed6fbff67c\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../openzeppelin/Math.sol\\\";\\nimport \\\"../interfaces/IController.sol\\\";\\nimport \\\"../interfaces/IControllable.sol\\\";\\nimport \\\"../interfaces/ITetuVaultV2.sol\\\";\\nimport \\\"../interfaces/ISplitter.sol\\\";\\nimport \\\"../interfaces/IStrategyV3.sol\\\";\\n\\nlibrary StrategyLib2 {\\n using SafeERC20 for IERC20;\\n\\n // *************************************************************\\n // CONSTANTS\\n // *************************************************************\\n\\n /// @dev Denominator for fee calculation.\\n uint internal constant FEE_DENOMINATOR = 100_000;\\n /// @notice 10% of total profit is sent to {performanceReceiver} before compounding\\n uint internal constant DEFAULT_PERFORMANCE_FEE = 10_000;\\n address internal constant DEFAULT_PERF_FEE_RECEIVER = 0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b;\\n /// @dev Denominator for compound ratio\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\n\\n // *************************************************************\\n // ERRORS\\n // *************************************************************\\n\\n string internal constant DENIED = \\\"SB: Denied\\\";\\n string internal constant TOO_HIGH = \\\"SB: Too high\\\";\\n string internal constant WRONG_VALUE = \\\"SB: Wrong value\\\";\\n\\n // *************************************************************\\n // EVENTS\\n // *************************************************************\\n\\n event CompoundRatioChanged(uint oldValue, uint newValue);\\n event StrategySpecificNameChanged(string name);\\n event EmergencyExit(address sender, uint amount);\\n event ManualClaim(address sender);\\n event InvestAll(uint balance);\\n event WithdrawAllToSplitter(uint amount);\\n event WithdrawToSplitter(uint amount, uint sent, uint balance);\\n event PerformanceFeeChanged(uint fee, address receiver, uint ratio);\\n\\n // *************************************************************\\n // CHECKS AND EMITS\\n // *************************************************************\\n\\n function _checkManualClaim(address controller) external {\\n onlyOperators(controller);\\n emit ManualClaim(msg.sender);\\n }\\n\\n function _checkInvestAll(address splitter, address asset) external returns (uint assetBalance) {\\n onlySplitter(splitter);\\n assetBalance = IERC20(asset).balanceOf(address(this));\\n emit InvestAll(assetBalance);\\n }\\n\\n function _checkSetupPerformanceFee(address controller, uint fee_, address receiver_, uint ratio_) internal {\\n onlyGovernance(controller);\\n require(fee_ <= FEE_DENOMINATOR, TOO_HIGH);\\n require(receiver_ != address(0), WRONG_VALUE);\\n require(ratio_ <= FEE_DENOMINATOR, TOO_HIGH);\\n emit PerformanceFeeChanged(fee_, receiver_, ratio_);\\n }\\n\\n // *************************************************************\\n // SETTERS\\n // *************************************************************\\n\\n function _changeCompoundRatio(IStrategyV3.BaseState storage baseState, address controller, uint newValue) external {\\n onlyPlatformVoterOrGov(controller);\\n require(newValue <= COMPOUND_DENOMINATOR, TOO_HIGH);\\n\\n uint oldValue = baseState.compoundRatio;\\n baseState.compoundRatio = newValue;\\n\\n emit CompoundRatioChanged(oldValue, newValue);\\n }\\n\\n function _changeStrategySpecificName(IStrategyV3.BaseState storage baseState, string calldata newName) external {\\n baseState.strategySpecificName = newName;\\n emit StrategySpecificNameChanged(newName);\\n }\\n\\n // *************************************************************\\n // RESTRICTIONS\\n // *************************************************************\\n\\n /// @dev Restrict access only for operators\\n function onlyOperators(address controller) public view {\\n require(IController(controller).isOperator(msg.sender), DENIED);\\n }\\n\\n /// @dev Restrict access only for governance\\n function onlyGovernance(address controller) public view {\\n require(IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for platform voter\\n function onlyPlatformVoterOrGov(address controller) public view {\\n require(IController(controller).platformVoter() == msg.sender || IController(controller).governance() == msg.sender, DENIED);\\n }\\n\\n /// @dev Restrict access only for splitter\\n function onlySplitter(address splitter) public view {\\n require(splitter == msg.sender, DENIED);\\n }\\n\\n // *************************************************************\\n // HELPERS\\n // *************************************************************\\n\\n function init(\\n IStrategyV3.BaseState storage baseState,\\n address controller_,\\n address splitter_\\n ) external {\\n baseState.asset = ISplitter(splitter_).asset();\\n baseState.splitter = splitter_;\\n baseState.performanceReceiver = DEFAULT_PERF_FEE_RECEIVER;\\n baseState.performanceFee = DEFAULT_PERFORMANCE_FEE;\\n\\n require(IControllable(splitter_).isController(controller_), WRONG_VALUE);\\n }\\n\\n function setupPerformanceFee(IStrategyV3.BaseState storage baseState, uint fee_, address receiver_, uint ratio_, address controller_) external {\\n _checkSetupPerformanceFee(controller_, fee_, receiver_, ratio_);\\n baseState.performanceFee = fee_;\\n baseState.performanceReceiver = receiver_;\\n baseState.performanceFeeRatio = ratio_;\\n }\\n\\n /// @notice Calculate withdrawn amount in USD using the {assetPrice}.\\n /// Revert if the amount is different from expected too much (high price impact)\\n /// @param balanceBefore Asset balance of the strategy before withdrawing\\n /// @param expectedWithdrewUSD Expected amount in USD, decimals are same to {_asset}\\n /// @param assetPrice Price of the asset, decimals 18\\n /// @return balance Current asset balance of the strategy\\n function checkWithdrawImpact(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) public view returns (uint balance) {\\n balance = IERC20(_asset).balanceOf(address(this));\\n if (assetPrice != 0 && expectedWithdrewUSD != 0) {\\n\\n uint withdrew = balance > balanceBefore ? balance - balanceBefore : 0;\\n uint withdrewUSD = withdrew * assetPrice / 1e18;\\n uint priceChangeTolerance = ITetuVaultV2(ISplitter(_splitter).vault()).withdrawFee();\\n uint difference = expectedWithdrewUSD > withdrewUSD ? expectedWithdrewUSD - withdrewUSD : 0;\\n require(difference * FEE_DENOMINATOR / expectedWithdrewUSD <= priceChangeTolerance, TOO_HIGH);\\n }\\n }\\n\\n function sendOnEmergencyExit(address controller, address asset, address splitter) external {\\n onlyOperators(controller);\\n\\n uint balance = IERC20(asset).balanceOf(address(this));\\n IERC20(asset).safeTransfer(splitter, balance);\\n emit EmergencyExit(msg.sender, balance);\\n }\\n\\n function _checkSplitterSenderAndGetBalance(address splitter, address asset) external view returns (uint balance) {\\n onlySplitter(splitter);\\n return IERC20(asset).balanceOf(address(this));\\n }\\n\\n function _withdrawAllToSplitterPostActions(\\n address _asset,\\n uint balanceBefore,\\n uint expectedWithdrewUSD,\\n uint assetPrice,\\n address _splitter\\n ) external {\\n uint balance = checkWithdrawImpact(\\n _asset,\\n balanceBefore,\\n expectedWithdrewUSD,\\n assetPrice,\\n _splitter\\n );\\n\\n if (balance != 0) {\\n IERC20(_asset).safeTransfer(_splitter, balance);\\n }\\n emit WithdrawAllToSplitter(balance);\\n }\\n\\n function _withdrawToSplitterPostActions(\\n uint amount,\\n uint balance,\\n address _asset,\\n address _splitter\\n ) external {\\n uint amountAdjusted = Math.min(amount, balance);\\n if (amountAdjusted != 0) {\\n IERC20(_asset).safeTransfer(_splitter, amountAdjusted);\\n }\\n emit WithdrawToSplitter(amount, amountAdjusted, balance);\\n }\\n}\\n\",\"keccak256\":\"0x63704dba8a701606a0100190d2e46e4c7599571d0b21467b9cd8f87468a7947b\",\"license\":\"BUSL-1.1\"},\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.17;\\n\\ninterface IBookkeeper {\\n /// @notice Register a new loan\\n /// @dev This function can be called by a pool adapter only\\n /// @param collateralAmount Amount of supplied collateral for the new loan\\n /// @param borrowedAmount Borrowed amount provided for the given {collateralAmount}\\n function onBorrow(uint collateralAmount, uint borrowedAmount) external;\\n\\n /// @notice Register loan payment\\n /// @dev This function can be called by a pool adapter only\\n /// @param withdrawnCollateral Amount of collateral received by the user during the repaying.\\n /// @param paidAmount Amount paid by the user during the repaying.\\n function onRepay(uint withdrawnCollateral, uint paidAmount) external;\\n\\n\\n /// @notice Save checkpoint for all pool adapters of the given {user_}\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function checkpoint(address[] memory tokens_) external returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate deltas that user would receive if he creates a checkpoint at the moment\\n /// @return deltaGains Total amount of gains for the {tokens_} by all pool adapter\\n /// @return deltaLosses Total amount of losses for the {tokens_} by all pool adapter\\n function previewCheckpoint(address user, address[] memory tokens_) external view returns (\\n uint[] memory deltaGains,\\n uint[] memory deltaLosses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the signer\\n /// for the current period, start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function startPeriod(address underlying_) external returns (\\n uint gains,\\n uint losses\\n );\\n\\n /// @notice Calculate total amount of gains and looses in underlying by all pool adapters of the {user_}\\n /// for the current period, DON'T start new period.\\n /// @param underlying_ Asset in which we calculate gains and loss. Assume that it's either collateral or borrow asset.\\n /// @return gains Total amount of gains (supply-profit) of the {user_} by all user's pool adapters\\n /// @return losses Total amount of losses (paid increases to debt) of the {user_} by all user's pool adapters\\n function previewPeriod(address underlying_, address user_) external view returns (uint gains, uint losses);\\n}\",\"keccak256\":\"0x98b7887d604ebcfaf28038c456c6c6893ce10f55b821f4c7c002dbc8055ea388\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\n/// @notice Keep and provide addresses of all application contracts\\ninterface IConverterController {\\n function governance() external view returns (address);\\n\\n // ********************* Health factor explanation ****************\\n // For example, a landing platform has: liquidity threshold = 0.85, LTV=0.8, LTV / LT = 1.0625\\n // For collateral $100 we can borrow $80. A liquidation happens if the cost of collateral will reduce below $85.\\n // We set min-health-factor = 1.1, target-health-factor = 1.3\\n // For collateral 100 we will borrow 100/1.3 = 76.92\\n //\\n // Collateral value 100 77 assume that collateral value is decreased at 100/77=1.3 times\\n // Collateral * LT 85 65.45\\n // Borrow value 65.38 65.38 but borrow value is the same as before\\n // Health factor 1.3 1.001 liquidation almost happens here (!)\\n //\\n /// So, if we have target factor 1.3, it means, that if collateral amount will decreases at 1.3 times\\n // and the borrow value won't change at the same time, the liquidation happens at that point.\\n // Min health factor marks the point at which a rebalancing must be made asap.\\n // *****************************************************************\\n\\n //#region ----------------------------------------------------- Configuration\\n\\n /// @notice min allowed health factor with decimals 2, must be >= 1e2\\n function minHealthFactor2() external view returns (uint16);\\n function setMinHealthFactor2(uint16 value_) external;\\n\\n /// @notice target health factor with decimals 2\\n /// @dev If the health factor is below/above min/max threshold, we need to make repay\\n /// or additional borrow and restore the health factor to the given target value\\n function targetHealthFactor2() external view returns (uint16);\\n function setTargetHealthFactor2(uint16 value_) external;\\n\\n /// @notice max allowed health factor with decimals 2\\n /// @dev For future versions, currently max health factor is not used\\n function maxHealthFactor2() external view returns (uint16);\\n /// @dev For future versions, currently max health factor is not used\\n function setMaxHealthFactor2(uint16 value_) external;\\n\\n /// @notice get current value of blocks per day. The value is set manually at first and can be auto-updated later\\n function blocksPerDay() external view returns (uint);\\n /// @notice set value of blocks per day manually and enable/disable auto update of this value\\n function setBlocksPerDay(uint blocksPerDay_, bool enableAutoUpdate_) external;\\n /// @notice Check if it's time to call updateBlocksPerDay()\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function isBlocksPerDayAutoUpdateRequired(uint periodInSeconds_) external view returns (bool);\\n /// @notice Recalculate blocksPerDay value\\n /// @param periodInSeconds_ Period of auto-update in seconds\\n function updateBlocksPerDay(uint periodInSeconds_) external;\\n\\n /// @notice 0 - new borrows are allowed, 1 - any new borrows are forbidden\\n function paused() external view returns (bool);\\n\\n /// @notice the given user is whitelisted and is allowed to make borrow/swap using TetuConverter\\n function isWhitelisted(address user_) external view returns (bool);\\n\\n /// @notice The size of the gap by which the debt should be increased upon repayment\\n /// Such gaps are required by AAVE pool adapters to workaround dust tokens problem\\n /// and be able to make full repayment.\\n /// @dev Debt gap is applied as following: toPay = debt * (DEBT_GAP_DENOMINATOR + debtGap) / DEBT_GAP_DENOMINATOR\\n function debtGap() external view returns (uint);\\n\\n /// @notice Allow to rebalance exist debts during burrow, see SCB-708\\n /// If the user already has a debt(s) for the given pair of collateral-borrow assets,\\n /// new borrow is made using exist pool adapter(s). Exist debt is rebalanced during the borrowing\\n /// in both directions, but the rebalancing is asymmetrically limited by thresholds\\n /// THRESHOLD_REBALANCE_XXX, see BorrowManager.\\n function rebalanceOnBorrowEnabled() external view returns (bool);\\n\\n //#endregion ----------------------------------------------------- Configuration\\n //#region ----------------------------------------------------- Core application contracts\\n\\n function tetuConverter() external view returns (address);\\n function borrowManager() external view returns (address);\\n function debtMonitor() external view returns (address);\\n function tetuLiquidator() external view returns (address);\\n function swapManager() external view returns (address);\\n function priceOracle() external view returns (address);\\n function bookkeeper() external view returns (address);\\n //#endregion ----------------------------------------------------- Core application contracts\\n\\n //#region ----------------------------------------------------- External contracts\\n /// @notice A keeper to control health and efficiency of the borrows\\n function keeper() external view returns (address);\\n /// @notice Controller of tetu-contracts-v2, that is allowed to update proxy contracts\\n function proxyUpdater() external view returns (address);\\n //#endregion ----------------------------------------------------- External contracts\\n}\\n\",\"keccak256\":\"0xff68dab4badf9543c9a0ae5a1314106f0a5b804e8b6669fbea6e2655eb3c741f\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IConverterControllerProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IConverterControllerProvider {\\n function controller() external view returns (address);\\n}\\n\",\"keccak256\":\"0x71dce61809acb75f9078290e90033ffe816a51f18b7cb296d161e278c36eec86\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\ninterface IPriceOracle {\\n /// @notice Return asset price in USD, decimals 18\\n function getAssetPrice(address asset) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xb11e653eb4d6d7c41f29ee1e3e498253cfa8df1aec3ff31ab527009b79bdb705\",\"license\":\"MIT\"},\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.8.17;\\n\\nimport \\\"./IConverterControllerProvider.sol\\\";\\n\\n/// @notice Main contract of the TetuConverter application\\n/// @dev Borrower (strategy) makes all operations via this contract only.\\ninterface ITetuConverter is IConverterControllerProvider {\\n\\n /// @notice Find possible borrow strategies and provide \\\"cost of money\\\" as interest for the period for each strategy\\n /// Result arrays of the strategy are ordered in ascending order of APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converters Array of available converters ordered in ascending order of APR.\\n /// Each item contains a result contract that should be used for conversion; it supports IConverter\\n /// This address should be passed to borrow-function during conversion.\\n /// The length of array is always equal to the count of available lending platforms.\\n /// Last items in array can contain zero addresses (it means they are not used)\\n /// @return collateralAmountsOut Amounts that should be provided as a collateral\\n /// @return amountToBorrowsOut Amounts that should be borrowed\\n /// This amount is not zero if corresponded converter is not zero.\\n /// @return aprs18 Interests on the use of {amountIn_} during the given period, decimals 18\\n function findBorrowStrategies(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external view returns (\\n address[] memory converters,\\n uint[] memory collateralAmountsOut,\\n uint[] memory amountToBorrowsOut,\\n int[] memory aprs18\\n );\\n\\n /// @notice Find best swap strategy and provide \\\"cost of money\\\" as interest for the period\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @return converter Result contract that should be used for conversion to be passed to borrow()\\n /// @return sourceAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return targetAmountOut Result amount of {targetToken_} after swap\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findSwapStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_\\n ) external returns (\\n address converter,\\n uint sourceAmountOut,\\n uint targetAmountOut,\\n int apr18\\n );\\n\\n /// @notice Find best conversion strategy (swap or borrow) and provide \\\"cost of money\\\" as interest for the period.\\n /// It calls both findBorrowStrategy and findSwapStrategy and selects a best strategy.\\n /// @dev This is writable function with read-only behavior.\\n /// It should be writable to be able to simulate real swap and get a real APR for swapping.\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\n /// See EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\n /// 0 is used by default\\n /// @param amountIn_ The meaning depends on entryData\\n /// For entryKind=0 it's max available amount of collateral\\n /// This amount must be approved to TetuConverter before the call.\\n /// For entryKind=2 we don't know amount of collateral before the call,\\n /// so it's necessary to approve large enough amount (or make infinity approve)\\n /// @param periodInBlocks_ Estimated period to keep target amount. It's required to compute APR\\n /// @return converter Result contract that should be used for conversion to be passed to borrow().\\n /// @return collateralAmountOut Amount of {sourceToken_} that should be swapped to get {targetToken_}\\n /// It can be different from the {sourceAmount_} for some entry kinds.\\n /// @return amountToBorrowOut Result amount of {targetToken_} after conversion\\n /// @return apr18 Interest on the use of {outMaxTargetAmount} during the given period, decimals 18\\n function findConversionStrategy(\\n bytes memory entryData_,\\n address sourceToken_,\\n uint amountIn_,\\n address targetToken_,\\n uint periodInBlocks_\\n ) external returns (\\n address converter,\\n uint collateralAmountOut,\\n uint amountToBorrowOut,\\n int apr18\\n );\\n\\n /// @notice Convert {collateralAmount_} to {amountToBorrow_} using {converter_}\\n /// Target amount will be transferred to {receiver_}.\\n /// Exist debts can be rebalanced fully or partially if {rebalanceOnBorrowEnabled} is ON\\n /// @dev Transferring of {collateralAmount_} by TetuConverter-contract must be approved by the caller before the call\\n /// Only whitelisted users are allowed to make borrows\\n /// @param converter_ A converter received from findBestConversionStrategy.\\n /// @param collateralAmount_ Amount of {collateralAsset_} to be converted.\\n /// This amount must be approved to TetuConverter before the call.\\n /// @param amountToBorrow_ Amount of {borrowAsset_} to be borrowed and sent to {receiver_}\\n /// @param receiver_ A receiver of borrowed amount\\n /// @return borrowedAmountOut Exact borrowed amount transferred to {receiver_}\\n function borrow(\\n address converter_,\\n address collateralAsset_,\\n uint collateralAmount_,\\n address borrowAsset_,\\n uint amountToBorrow_,\\n address receiver_\\n ) external returns (\\n uint borrowedAmountOut\\n );\\n\\n /// @notice Full or partial repay of the borrow\\n /// @dev A user should transfer {amountToRepay_} to TetuConverter before calling repay()\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// A user should transfer {amountToRepay_} to TetuConverter before calling repay().\\n /// You can know exact total amount of debt using {getStatusCurrent}.\\n /// if the amount exceed total amount of the debt:\\n /// - the debt will be fully repaid\\n /// - remain amount will be swapped from {borrowAsset_} to {collateralAsset_}\\n /// This amount should be calculated with taking into account possible debt gap,\\n /// You should call getDebtAmountCurrent(debtGap = true) to get this amount.\\n /// @param receiver_ A receiver of the collateral that will be withdrawn after the repay\\n /// The remained amount of borrow asset will be returned to the {receiver_} too\\n /// @return collateralAmountOut Exact collateral amount transferred to {collateralReceiver_}\\n /// If TetuConverter is not able to make the swap, it reverts\\n /// @return returnedBorrowAmountOut A part of amount-to-repay that wasn't converted to collateral asset\\n /// because of any reasons (i.e. there is no available conversion strategy)\\n /// This amount is returned back to the collateralReceiver_\\n /// @return swappedLeftoverCollateralOut A part of collateral received through the swapping\\n /// @return swappedLeftoverBorrowOut A part of amountToRepay_ that was swapped\\n function repay(\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_,\\n address receiver_\\n ) external returns (\\n uint collateralAmountOut,\\n uint returnedBorrowAmountOut,\\n uint swappedLeftoverCollateralOut,\\n uint swappedLeftoverBorrowOut\\n );\\n\\n /// @notice Estimate result amount after making full or partial repay\\n /// @dev It works in exactly same way as repay() but don't make actual repay\\n /// Anyway, the function is write, not read-only, because it makes updateStatus()\\n /// @param user_ user whose amount-to-repay will be calculated\\n /// @param amountToRepay_ Amount of borrowed asset to repay.\\n /// This amount should be calculated without possible debt gap.\\n /// In this way it's differ from {repay}\\n /// @return collateralAmountOut Total collateral amount to be returned after repay in exchange of {amountToRepay_}\\n /// @return swappedAmountOut A part of {collateralAmountOut} that were received by direct swap\\n function quoteRepay(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n uint amountToRepay_\\n ) external returns (\\n uint collateralAmountOut,\\n uint swappedAmountOut\\n );\\n\\n /// @notice Update status in all opened positions\\n /// After this call getDebtAmount will be able to return exact amount to repay\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountCurrent(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice Total amount of borrow tokens that should be repaid to close the borrow completely.\\n /// @param user_ user whose debts will be returned\\n /// @param useDebtGap_ Calculate exact value of the debt (false) or amount to pay (true)\\n /// Exact value of the debt can be a bit different from amount to pay, i.e. AAVE has dust tokens problem.\\n /// Exact amount of debt should be used to calculate shared price, amount to pay - for repayment\\n /// @return totalDebtAmountOut Borrowed amount that should be repaid to pay off the loan in full\\n /// @return totalCollateralAmountOut Amount of collateral that should be received after paying off the loan\\n function getDebtAmountStored(\\n address user_,\\n address collateralAsset_,\\n address borrowAsset_,\\n bool useDebtGap_\\n ) external view returns (\\n uint totalDebtAmountOut,\\n uint totalCollateralAmountOut\\n );\\n\\n /// @notice User needs to redeem some collateral amount. Calculate an amount of borrow token that should be repaid\\n /// @param user_ user whose debts will be returned\\n /// @param collateralAmountRequired_ Amount of collateral required by the user\\n /// @return borrowAssetAmount Borrowed amount that should be repaid to receive back following amount of collateral:\\n /// amountToReceive = collateralAmountRequired_ - unobtainableCollateralAssetAmount\\n /// @return unobtainableCollateralAssetAmount A part of collateral that cannot be obtained in any case\\n /// even if all borrowed amount will be returned.\\n /// If this amount is not 0, you ask to get too much collateral.\\n function estimateRepay(\\n address user_,\\n address collateralAsset_,\\n uint collateralAmountRequired_,\\n address borrowAsset_\\n ) external view returns (\\n uint borrowAssetAmount,\\n uint unobtainableCollateralAssetAmount\\n );\\n\\n /// @notice Transfer all reward tokens to {receiver_}\\n /// @return rewardTokensOut What tokens were transferred. Same reward token can appear in the array several times\\n /// @return amountsOut Amounts of transferred rewards, the array is synced with {rewardTokens}\\n function claimRewards(address receiver_) external returns (\\n address[] memory rewardTokensOut,\\n uint[] memory amountsOut\\n );\\n\\n /// @notice Swap {amountIn_} of {assetIn_} to {assetOut_} and send result amount to {receiver_}\\n /// The swapping is made using TetuLiquidator with checking price impact using embedded price oracle.\\n /// @param amountIn_ Amount of {assetIn_} to be swapped.\\n /// It should be transferred on balance of the TetuConverter before the function call\\n /// @param receiver_ Result amount will be sent to this address\\n /// @param priceImpactToleranceSource_ Price impact tolerance for liquidate-call, decimals = 100_000\\n /// @param priceImpactToleranceTarget_ Price impact tolerance for price-oracle-check, decimals = 100_000\\n /// @return amountOut The amount of {assetOut_} that has been sent to the receiver\\n function safeLiquidate(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n address receiver_,\\n uint priceImpactToleranceSource_,\\n uint priceImpactToleranceTarget_\\n ) external returns (\\n uint amountOut\\n );\\n\\n /// @notice Check if {amountOut_} is too different from the value calculated directly using price oracle prices\\n /// @return Price difference is ok for the given {priceImpactTolerance_}\\n function isConversionValid(\\n address assetIn_,\\n uint amountIn_,\\n address assetOut_,\\n uint amountOut_,\\n uint priceImpactTolerance_\\n ) external view returns (bool);\\n\\n /// @notice Close given borrow and return collateral back to the user, governance only\\n /// @dev The pool adapter asks required amount-to-repay from the user internally\\n /// @param poolAdapter_ The pool adapter that represents the borrow\\n /// @param closePosition Close position after repay\\n /// Usually it should be true, because the function always tries to repay all debt\\n /// false can be used if user doesn't have enough amount to pay full debt\\n /// and we are trying to pay \\\"as much as possible\\\"\\n /// @return collateralAmountOut Amount of collateral returned to the user\\n /// @return repaidAmountOut Amount of borrow asset paid to the lending platform\\n function repayTheBorrow(address poolAdapter_, bool closePosition) external returns (\\n uint collateralAmountOut,\\n uint repaidAmountOut\\n );\\n\\n /// @notice Get active borrows of the user with given collateral/borrowToken\\n /// @dev Simple access to IDebtMonitor.getPositions\\n /// @return poolAdaptersOut The instances of IPoolAdapter\\n function getPositions(address user_, address collateralToken_, address borrowedToken_) external view returns (\\n address[] memory poolAdaptersOut\\n );\\n\\n /// @notice Save token from TC-balance to {receiver}\\n /// @dev Normally TetuConverter doesn't have any tokens on balance, they can appear there accidentally only\\n function salvage(address receiver, address token, uint amount) external;\\n}\\n\",\"keccak256\":\"0x87ac3099e1254509929511509c207ecee9a665a3b43d7ee5b98e2ab0d639416d\",\"license\":\"MIT\"},\"contracts/integrations/uniswap/IUniswapV3Pool.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport './IUniswapV3PoolImmutables.sol';\\r\\nimport './IUniswapV3PoolState.sol';\\r\\nimport './IUniswapV3PoolDerivedState.sol';\\r\\nimport './IUniswapV3PoolActions.sol';\\r\\nimport './IUniswapV3PoolOwnerActions.sol';\\r\\nimport './IUniswapV3PoolEvents.sol';\\r\\n\\r\\n/// @title The interface for a Uniswap V3 Pool\\r\\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\\r\\n/// to the ERC20 specification\\r\\n/// @dev The pool interface is broken up into many smaller pieces\\r\\ninterface IUniswapV3Pool is\\r\\nIUniswapV3PoolImmutables,\\r\\nIUniswapV3PoolState,\\r\\nIUniswapV3PoolDerivedState,\\r\\nIUniswapV3PoolActions,\\r\\nIUniswapV3PoolOwnerActions,\\r\\nIUniswapV3PoolEvents\\r\\n{}\\r\\n\",\"keccak256\":\"0x86cf4965c72b977a295ec03d120d32f6e4c5f06a59a927a79cb19648aca467d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissionless pool actions\\r\\n/// @notice Contains pool methods that can be called by anyone\\r\\ninterface IUniswapV3PoolActions {\\r\\n /// @notice Sets the initial price for the pool\\r\\n /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value\\r\\n /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96\\r\\n function initialize(uint160 sqrtPriceX96) external;\\r\\n\\r\\n /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback\\r\\n /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends\\r\\n /// on tickLower, tickUpper, the amount of liquidity, and the current price.\\r\\n /// @param recipient The address for which the liquidity will be created\\r\\n /// @param tickLower The lower tick of the position in which to add liquidity\\r\\n /// @param tickUpper The upper tick of the position in which to add liquidity\\r\\n /// @param amount The amount of liquidity to mint\\r\\n /// @param data Any data that should be passed through to the callback\\r\\n /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback\\r\\n function mint(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount,\\r\\n bytes calldata data\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Collects tokens owed to a position\\r\\n /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.\\r\\n /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or\\r\\n /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the\\r\\n /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.\\r\\n /// @param recipient The address which should receive the fees collected\\r\\n /// @param tickLower The lower tick of the position for which to collect fees\\r\\n /// @param tickUpper The upper tick of the position for which to collect fees\\r\\n /// @param amount0Requested How much token0 should be withdrawn from the fees owed\\r\\n /// @param amount1Requested How much token1 should be withdrawn from the fees owed\\r\\n /// @return amount0 The amount of fees collected in token0\\r\\n /// @return amount1 The amount of fees collected in token1\\r\\n function collect(\\r\\n address recipient,\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n\\r\\n /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position\\r\\n /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0\\r\\n /// @dev Fees must be collected separately via a call to #collect\\r\\n /// @param tickLower The lower tick of the position for which to burn liquidity\\r\\n /// @param tickUpper The upper tick of the position for which to burn liquidity\\r\\n /// @param amount How much liquidity to burn\\r\\n /// @return amount0 The amount of token0 sent to the recipient\\r\\n /// @return amount1 The amount of token1 sent to the recipient\\r\\n function burn(\\r\\n int24 tickLower,\\r\\n int24 tickUpper,\\r\\n uint128 amount\\r\\n ) external returns (uint256 amount0, uint256 amount1);\\r\\n\\r\\n /// @notice Swap token0 for token1, or token1 for token0\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback\\r\\n /// @param recipient The address to receive the output of the swap\\r\\n /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0\\r\\n /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)\\r\\n /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this\\r\\n /// value after the swap. If one for zero, the price cannot be greater than this value after the swap\\r\\n /// @param data Any data to be passed through to the callback\\r\\n /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive\\r\\n /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive\\r\\n function swap(\\r\\n address recipient,\\r\\n bool zeroForOne,\\r\\n int256 amountSpecified,\\r\\n uint160 sqrtPriceLimitX96,\\r\\n bytes calldata data\\r\\n ) external returns (int256 amount0, int256 amount1);\\r\\n\\r\\n /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback\\r\\n /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback\\r\\n /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling\\r\\n /// with 0 amount{0,1} and sending the donation amount(s) from the callback\\r\\n /// @param recipient The address which will receive the token0 and token1 amounts\\r\\n /// @param amount0 The amount of token0 to send\\r\\n /// @param amount1 The amount of token1 to send\\r\\n /// @param data Any data to be passed through to the callback\\r\\n function flash(\\r\\n address recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n bytes calldata data\\r\\n ) external;\\r\\n\\r\\n /// @notice Increase the maximum number of price and liquidity observations that this pool will store\\r\\n /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to\\r\\n /// the input observationCardinalityNext.\\r\\n /// @param observationCardinalityNext The desired minimum number of observations for the pool to store\\r\\n function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;\\r\\n}\\r\\n\",\"keccak256\":\"0x1d1a257f92723ba61e9139010be871f5e18c4541e174442a2905ecd339dfa60d\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolDerivedState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that is not stored\\r\\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\\r\\n/// blockchain. The functions here may have variable gas costs.\\r\\ninterface IUniswapV3PoolDerivedState {\\r\\n /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\\r\\n /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\\r\\n /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\\r\\n /// you must call it with secondsAgos = [3600, 0].\\r\\n /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\\r\\n /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\\r\\n /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\\r\\n /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\\r\\n /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\\r\\n /// timestamp\\r\\n function observe(uint32[] calldata secondsAgos)\\r\\n external\\r\\n view\\r\\n returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\\r\\n\\r\\n /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\\r\\n /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\\r\\n /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\\r\\n /// snapshot is taken and the second snapshot is taken.\\r\\n /// @param tickLower The lower tick of the range\\r\\n /// @param tickUpper The upper tick of the range\\r\\n /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\\r\\n /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\\r\\n /// @return secondsInside The snapshot of seconds per liquidity for the range\\r\\n function snapshotCumulativesInside(int24 tickLower, int24 tickUpper)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n int56 tickCumulativeInside,\\r\\n uint160 secondsPerLiquidityInsideX128,\\r\\n uint32 secondsInside\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x7237f53b22f1d98dfa1ed40e296f0710e3ecc8d388d125f9daab803125ae91d9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolEvents.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Events emitted by a pool\\r\\n/// @notice Contains all events emitted by the pool\\r\\ninterface IUniswapV3PoolEvents {\\r\\n /// @notice Emitted exactly once by a pool when #initialize is first called on the pool\\r\\n /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize\\r\\n /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96\\r\\n /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool\\r\\n event Initialize(uint160 sqrtPriceX96, int24 tick);\\r\\n\\r\\n /// @notice Emitted when liquidity is minted for a given position\\r\\n /// @param sender The address that minted the liquidity\\r\\n /// @param owner The owner of the position and recipient of any minted liquidity\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity minted to the position range\\r\\n /// @param amount0 How much token0 was required for the minted liquidity\\r\\n /// @param amount1 How much token1 was required for the minted liquidity\\r\\n event Mint(\\r\\n address sender,\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when fees are collected by the owner of a position\\r\\n /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees\\r\\n /// @param owner The owner of the position for which fees are collected\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount0 The amount of token0 fees collected\\r\\n /// @param amount1 The amount of token1 fees collected\\r\\n event Collect(\\r\\n address indexed owner,\\r\\n address recipient,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount0,\\r\\n uint128 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted when a position's liquidity is removed\\r\\n /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect\\r\\n /// @param owner The owner of the position for which liquidity is removed\\r\\n /// @param tickLower The lower tick of the position\\r\\n /// @param tickUpper The upper tick of the position\\r\\n /// @param amount The amount of liquidity to remove\\r\\n /// @param amount0 The amount of token0 withdrawn\\r\\n /// @param amount1 The amount of token1 withdrawn\\r\\n event Burn(\\r\\n address indexed owner,\\r\\n int24 indexed tickLower,\\r\\n int24 indexed tickUpper,\\r\\n uint128 amount,\\r\\n uint256 amount0,\\r\\n uint256 amount1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any swaps between token0 and token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the output of the swap\\r\\n /// @param amount0 The delta of the token0 balance of the pool\\r\\n /// @param amount1 The delta of the token1 balance of the pool\\r\\n /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96\\r\\n /// @param liquidity The liquidity of the pool after the swap\\r\\n /// @param tick The log base 1.0001 of price of the pool after the swap\\r\\n event Swap(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n int256 amount0,\\r\\n int256 amount1,\\r\\n uint160 sqrtPriceX96,\\r\\n uint128 liquidity,\\r\\n int24 tick\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for any flashes of token0/token1\\r\\n /// @param sender The address that initiated the swap call, and that received the callback\\r\\n /// @param recipient The address that received the tokens from flash\\r\\n /// @param amount0 The amount of token0 that was flashed\\r\\n /// @param amount1 The amount of token1 that was flashed\\r\\n /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee\\r\\n /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee\\r\\n event Flash(\\r\\n address indexed sender,\\r\\n address indexed recipient,\\r\\n uint256 amount0,\\r\\n uint256 amount1,\\r\\n uint256 paid0,\\r\\n uint256 paid1\\r\\n );\\r\\n\\r\\n /// @notice Emitted by the pool for increases to the number of observations that can be stored\\r\\n /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index\\r\\n /// just before a mint/swap/burn.\\r\\n /// @param observationCardinalityNextOld The previous value of the next observation cardinality\\r\\n /// @param observationCardinalityNextNew The updated value of the next observation cardinality\\r\\n event IncreaseObservationCardinalityNext(\\r\\n uint16 observationCardinalityNextOld,\\r\\n uint16 observationCardinalityNextNew\\r\\n );\\r\\n\\r\\n /// @notice Emitted when the protocol fee is changed by the pool\\r\\n /// @param feeProtocol0Old The previous value of the token0 protocol fee\\r\\n /// @param feeProtocol1Old The previous value of the token1 protocol fee\\r\\n /// @param feeProtocol0New The updated value of the token0 protocol fee\\r\\n /// @param feeProtocol1New The updated value of the token1 protocol fee\\r\\n event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New);\\r\\n\\r\\n /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner\\r\\n /// @param sender The address that collects the protocol fees\\r\\n /// @param recipient The address that receives the collected protocol fees\\r\\n /// @param amount0 The amount of token0 protocol fees that is withdrawn\\r\\n /// @param amount0 The amount of token1 protocol fees that is withdrawn\\r\\n event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xc69205cdcb46aef780b9507aca9c7d67193be7219e1cd147e9dd7bcc7d8699dd\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolImmutables.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that never changes\\r\\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\\r\\ninterface IUniswapV3PoolImmutables {\\r\\n /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\\r\\n /// @return The contract address\\r\\n function factory() external view returns (address);\\r\\n\\r\\n /// @notice The first of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token0() external view returns (address);\\r\\n\\r\\n /// @notice The second of the two tokens of the pool, sorted by address\\r\\n /// @return The token contract address\\r\\n function token1() external view returns (address);\\r\\n\\r\\n /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\\r\\n /// @return The fee\\r\\n function fee() external view returns (uint24);\\r\\n\\r\\n /// @notice The pool tick spacing\\r\\n /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\\r\\n /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\\r\\n /// This value is an int24 to avoid casting even though it is always positive.\\r\\n /// @return The tick spacing\\r\\n function tickSpacing() external view returns (int24);\\r\\n\\r\\n /// @notice The maximum amount of position liquidity that can use any tick in the range\\r\\n /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\\r\\n /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\\r\\n /// @return The max amount of liquidity per tick\\r\\n function maxLiquidityPerTick() external view returns (uint128);\\r\\n}\\r\\n\",\"keccak256\":\"0xefd00c9927c2a396d34157fd71f4701b68ab7c22df41a71ac1e4236d7e3a8d47\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolOwnerActions.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Permissioned pool actions\\r\\n/// @notice Contains pool methods that may only be called by the factory owner\\r\\ninterface IUniswapV3PoolOwnerActions {\\r\\n /// @notice Set the denominator of the protocol's % share of the fees\\r\\n /// @param feeProtocol0 new protocol fee for token0 of the pool\\r\\n /// @param feeProtocol1 new protocol fee for token1 of the pool\\r\\n function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external;\\r\\n\\r\\n /// @notice Collect the protocol fee accrued to the pool\\r\\n /// @param recipient The address to which collected protocol fees should be sent\\r\\n /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1\\r\\n /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0\\r\\n /// @return amount0 The protocol fee collected in token0\\r\\n /// @return amount1 The protocol fee collected in token1\\r\\n function collectProtocol(\\r\\n address recipient,\\r\\n uint128 amount0Requested,\\r\\n uint128 amount1Requested\\r\\n ) external returns (uint128 amount0, uint128 amount1);\\r\\n}\\r\\n\",\"keccak256\":\"0xf3cd2d63d286ef834ccc14a80edfef98443043efad294b5ea52d5b070835a2c9\",\"license\":\"GPL-2.0-or-later\"},\"contracts/integrations/uniswap/IUniswapV3PoolState.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-2.0-or-later\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @title Pool state that can change\\r\\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\\r\\n/// per transaction\\r\\ninterface IUniswapV3PoolState {\\r\\n /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\\r\\n /// when accessed externally.\\r\\n /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\\r\\n /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\\r\\n /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\\r\\n /// boundary.\\r\\n /// observationIndex The index of the last oracle observation that was written,\\r\\n /// observationCardinality The current maximum number of observations stored in the pool,\\r\\n /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\\r\\n /// feeProtocol The protocol fee for both tokens of the pool.\\r\\n /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\\r\\n /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\\r\\n /// unlocked Whether the pool is currently locked to reentrancy\\r\\n function slot0()\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint160 sqrtPriceX96,\\r\\n int24 tick,\\r\\n uint16 observationIndex,\\r\\n uint16 observationCardinality,\\r\\n uint16 observationCardinalityNext,\\r\\n uint8 feeProtocol,\\r\\n bool unlocked\\r\\n );\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal0X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\\r\\n /// @dev This value can overflow the uint256\\r\\n function feeGrowthGlobal1X128() external view returns (uint256);\\r\\n\\r\\n /// @notice The amounts of token0 and token1 that are owed to the protocol\\r\\n /// @dev Protocol fees will never exceed uint128 max in either token\\r\\n function protocolFees() external view returns (uint128 token0, uint128 token1);\\r\\n\\r\\n /// @notice The currently in range liquidity available to the pool\\r\\n /// @dev This value has no relationship to the total liquidity across all ticks\\r\\n function liquidity() external view returns (uint128);\\r\\n\\r\\n /// @notice Look up information about a specific tick in the pool\\r\\n /// @param tick The tick to look up\\r\\n /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\\r\\n /// tick upper,\\r\\n /// liquidityNet how much liquidity changes when the pool price crosses the tick,\\r\\n /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\\r\\n /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\\r\\n /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\\r\\n /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\\r\\n /// secondsOutside the seconds spent on the other side of the tick from the current tick,\\r\\n /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\\r\\n /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\\r\\n /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\\r\\n /// a specific position.\\r\\n function ticks(int24 tick)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 liquidityGross,\\r\\n int128 liquidityNet,\\r\\n uint256 feeGrowthOutside0X128,\\r\\n uint256 feeGrowthOutside1X128,\\r\\n int56 tickCumulativeOutside,\\r\\n uint160 secondsPerLiquidityOutsideX128,\\r\\n uint32 secondsOutside,\\r\\n bool initialized\\r\\n );\\r\\n\\r\\n /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\\r\\n function tickBitmap(int16 wordPosition) external view returns (uint256);\\r\\n\\r\\n /// @notice Returns the information about a position by the position's key\\r\\n /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\\r\\n /// @return _liquidity The amount of liquidity in the position,\\r\\n /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\\r\\n /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\\r\\n function positions(bytes32 key)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint128 _liquidity,\\r\\n uint256 feeGrowthInside0LastX128,\\r\\n uint256 feeGrowthInside1LastX128,\\r\\n uint128 tokensOwed0,\\r\\n uint128 tokensOwed1\\r\\n );\\r\\n\\r\\n /// @notice Returns data about a specific observation index\\r\\n /// @param index The element of the observations array to fetch\\r\\n /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\\r\\n /// ago, rather than at a specific index in the array.\\r\\n /// @return blockTimestamp The timestamp of the observation,\\r\\n /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\\r\\n /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\\r\\n /// Returns initialized whether the observation has been initialized and the values are safe to use\\r\\n function observations(uint256 index)\\r\\n external\\r\\n view\\r\\n returns (\\r\\n uint32 blockTimestamp,\\r\\n int56 tickCumulative,\\r\\n uint160 secondsPerLiquidityCumulativeX128,\\r\\n bool initialized\\r\\n );\\r\\n}\\r\\n\",\"keccak256\":\"0x397cb2b62ca15d8e4b276b2aaf4cd9720a44f524533e37fb53953f930d9d0e92\",\"license\":\"GPL-2.0-or-later\"},\"contracts/interfaces/IConverterStrategyBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\n\\r\\n/// @notice Allow to share declaration of ConverterStrategyBaseState with libraries\\r\\ninterface IConverterStrategyBase {\\r\\n struct ConverterStrategyBaseState {\\r\\n /// @dev Amount of underlying assets invested to the pool.\\r\\n uint investedAssets;\\r\\n\\r\\n /// @dev Linked Tetu Converter\\r\\n ITetuConverter converter;\\r\\n\\r\\n /// @notice Percent of asset amount that can be not invested, it's allowed to just keep it on balance\\r\\n /// decimals = {DENOMINATOR}\\r\\n /// @dev We need this threshold to avoid numerous conversions of small amounts\\r\\n uint reinvestThresholdPercent;\\r\\n\\r\\n /// @notice Current debt to the insurance.\\r\\n /// It's increased when insurance covers any losses related to swapping and borrow-debts-paying.\\r\\n /// It's not changed when insurance covers losses/receives profit that appeared after price changing.\\r\\n /// The strategy covers this debt on each hardwork using the profit (rewards, fees)\\r\\n int debtToInsurance;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50-1] __gap;\\r\\n }\\r\\n}\",\"keccak256\":\"0x0be4f2ba25d955dfa6c9f821ecb466c3ae78f025ad2a85d83d11e22d850047ea\",\"license\":\"MIT\"},\"contracts/interfaces/IPoolProportionsProvider.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\r\\npragma solidity 0.8.17;\\r\\n\\r\\ninterface IPoolProportionsProvider {\\r\\n /// @notice Calculate proportions of [underlying, not-underlying] required by the internal pool of the strategy\\r\\n /// @return Proportion of the not-underlying [0...1e18]\\r\\n function getPropNotUnderlying18() external view returns (uint);\\r\\n}\\r\\n\",\"keccak256\":\"0x6722552632531ac63c23ddc5a3a104647a3e4a0d4c417ab9051c47ed49bc826c\",\"license\":\"MIT\"},\"contracts/libs/AppErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice List of all errors generated by the application\\r\\n/// Each error should have unique code TS-XXX and descriptive comment\\r\\nlibrary AppErrors {\\r\\n /// @notice Provided address should be not zero\\r\\n string public constant ZERO_ADDRESS = \\\"TS-1 zero address\\\";\\r\\n\\r\\n /// @notice A pair of the tokens cannot be found in the factory of uniswap pairs\\r\\n string public constant UNISWAP_PAIR_NOT_FOUND = \\\"TS-2 pair not found\\\";\\r\\n\\r\\n /// @notice Lengths not matched\\r\\n string public constant WRONG_LENGTHS = \\\"TS-4 wrong lengths\\\";\\r\\n\\r\\n /// @notice Unexpected zero balance\\r\\n string public constant ZERO_BALANCE = \\\"TS-5 zero balance\\\";\\r\\n\\r\\n string public constant ITEM_NOT_FOUND = \\\"TS-6 not found\\\";\\r\\n\\r\\n string public constant NOT_ENOUGH_BALANCE = \\\"TS-7 not enough balance\\\";\\r\\n\\r\\n /// @notice Price oracle returns zero price\\r\\n string public constant ZERO_PRICE = \\\"TS-8 zero price\\\";\\r\\n\\r\\n string public constant WRONG_VALUE = \\\"TS-9 wrong value\\\";\\r\\n\\r\\n /// @notice TetuConvertor wasn't able to make borrow, i.e. borrow-strategy wasn't found\\r\\n string public constant ZERO_AMOUNT_BORROWED = \\\"TS-10 zero borrowed amount\\\";\\r\\n\\r\\n string public constant WITHDRAW_TOO_MUCH = \\\"TS-11 try to withdraw too much\\\";\\r\\n\\r\\n string public constant UNKNOWN_ENTRY_KIND = \\\"TS-12 unknown entry kind\\\";\\r\\n\\r\\n string public constant ONLY_TETU_CONVERTER = \\\"TS-13 only TetuConverter\\\";\\r\\n\\r\\n string public constant WRONG_ASSET = \\\"TS-14 wrong asset\\\";\\r\\n\\r\\n string public constant NO_LIQUIDATION_ROUTE = \\\"TS-15 No liquidation route\\\";\\r\\n\\r\\n string public constant PRICE_IMPACT = \\\"TS-16 price impact\\\";\\r\\n\\r\\n /// @notice tetuConverter_.repay makes swap internally. It's not efficient and not allowed\\r\\n string public constant REPAY_MAKES_SWAP = \\\"TS-17 can not convert back\\\";\\r\\n\\r\\n string public constant NO_INVESTMENTS = \\\"TS-18 no investments\\\";\\r\\n\\r\\n string public constant INCORRECT_LENGTHS = \\\"TS-19 lengths\\\";\\r\\n\\r\\n /// @notice We expect increasing of the balance, but it was decreased\\r\\n string public constant BALANCE_DECREASE = \\\"TS-20 balance decrease\\\";\\r\\n\\r\\n /// @notice Prices changed and invested assets amount was increased on S, value of S is too high\\r\\n string public constant EARNED_AMOUNT_TOO_HIGH = \\\"TS-21 earned too high\\\";\\r\\n\\r\\n string public constant GOVERNANCE_ONLY = \\\"TS-22 governance only\\\";\\r\\n\\r\\n string public constant ZERO_VALUE = \\\"TS-24 zero value\\\";\\r\\n\\r\\n string public constant INCORRECT_SWAP_BY_AGG_PARAM = \\\"TS-25 swap by agg\\\";\\r\\n\\r\\n string public constant OVER_COLLATERAL_DETECTED = \\\"TS-27 over-collateral\\\";\\r\\n\\r\\n string public constant NOT_IMPLEMENTED = \\\"TS-28 not implemented\\\";\\r\\n\\r\\n /// @notice You are not allowed to make direct debt if a NOT-DUST reverse debt exists and visa verse.\\r\\n string public constant OPPOSITE_DEBT_EXISTS = \\\"TS-29 opposite debt exists\\\";\\r\\n\\r\\n string public constant INVALID_VALUE = \\\"TS-30 invalid value\\\";\\r\\n\\r\\n string public constant TOO_HIGH = \\\"TS-32 too high value\\\";\\r\\n\\r\\n /// @notice BorrowLib has recursive call, sub-calls are not allowed\\r\\n /// This error can happen if allowed proportion is too small, i.e. 0.0004 : (1-0.0004)\\r\\n /// Such situation can happen if amount to swap is almost equal to the amount of the token in the current tick,\\r\\n /// so swap will move us close to the border between ticks.\\r\\n /// It was decided, that it's ok to have revert in that case\\r\\n /// We can change this behavior by changing BorrowLib.rebalanceRepayBorrow implementation:\\r\\n /// if amount-to-repay passed to _repayDebt is too small to be used,\\r\\n /// we should increase it min amount required to make repay successfully (amount must be > threshold)\\r\\n /// Previously it was error NOT_ALLOWED = \\\"TS23: not allowed\\\", see issues SCB-777, SCB-818\\r\\n string public constant TOO_DEEP_RECURSION_BORROW_LIB = \\\"TS-33 too deep recursion\\\";\\r\\n}\\r\\n\",\"keccak256\":\"0x1400c631697434c991de2bfadcac7a0164a87be41a2cb683ed7f4fc75798d3e8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/AppLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/SafeERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IController.sol\\\";\\r\\n\\r\\n/// @notice Common internal utils\\r\\nlibrary AppLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n /// @notice 1% gap to cover possible liquidation inefficiency\\r\\n /// @dev We assume that: conversion-result-calculated-by-prices - liquidation-result <= the-gap\\r\\n uint internal constant GAP_CONVERSION = 1_000;\\r\\n /// @dev Absolute value for any token\\r\\n uint internal constant DEFAULT_LIQUIDATION_THRESHOLD = 100_000;\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @notice Any amount less than the following is dust\\r\\n uint public constant DUST_AMOUNT_TOKENS = 100;\\r\\n\\r\\n /// @notice Unchecked increment for for-cycles\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}\\r\\n /// @dev Should NOT be used for third-party pools\\r\\n function approveIfNeeded(address token, uint amount, address spender) internal {\\r\\n if (IERC20(token).allowance(address(this), spender) < amount) {\\r\\n // infinite approve, 2*255 is more gas efficient then type(uint).max\\r\\n IERC20(token).approve(spender, 2 ** 255);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make approve of {token} to unsafe {spender} (like an aggregator) for fixed {amount}\\r\\n function approveForced(address token, uint amount, address spender) internal {\\r\\n IERC20(token).approve(spender, amount);\\r\\n }\\r\\n\\r\\n function balance(address token) internal view returns (uint) {\\r\\n return IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _getPricesAndDecs(IPriceOracle priceOracle, address[] memory tokens_, uint len) internal view returns (\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n prices = new uint[](len);\\r\\n decs = new uint[](len);\\r\\n {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n decs[i] = 10 ** IERC20Metadata(tokens_[i]).decimals();\\r\\n prices[i] = priceOracle.getAssetPrice(tokens_[i]);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Find index of the given {asset_} in array {tokens_}, return type(uint).max if not found\\r\\n function getAssetIndex(address[] memory tokens_, address asset_) internal pure returns (uint) {\\r\\n uint len = tokens_.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (tokens_[i] == asset_) {\\r\\n return i;\\r\\n }\\r\\n }\\r\\n return type(uint).max;\\r\\n }\\r\\n\\r\\n function _getLiquidator(address controller_) internal view returns (ITetuLiquidator) {\\r\\n return ITetuLiquidator(IController(controller_).liquidator());\\r\\n }\\r\\n\\r\\n function _getPriceOracle(ITetuConverter converter_) internal view returns (IPriceOracle) {\\r\\n return IPriceOracle(IConverterController(converter_.controller()).priceOracle());\\r\\n }\\r\\n\\r\\n /// @notice Calculate liquidation threshold, use default value if the threshold is not set\\r\\n /// It's allowed to set any not-zero threshold, it this case default value is not used\\r\\n /// @dev This function should be applied to the threshold at the moment of the reading its value from the storage.\\r\\n /// So, if we pass {mapping(address => uint) storage liquidationThresholds}, the threshold can be zero\\r\\n /// bug if we pass {uint liquidationThreshold} to a function, the threshold should be not zero\\r\\n function _getLiquidationThreshold(uint threshold) internal pure returns (uint) {\\r\\n return threshold == 0\\r\\n ? AppLib.DEFAULT_LIQUIDATION_THRESHOLD\\r\\n : threshold;\\r\\n }\\r\\n\\r\\n /// @notice Return a-b OR zero if a < b\\r\\n function sub0(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a - b : 0;\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x7dc2bddc5940fbdc22a6eb59637a71345999fead987b7e5dec86d3e64fb85dd4\",\"license\":\"BUSL-1.1\"},\"contracts/libs/BorrowLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../strategies/ConverterStrategyBaseLib.sol\\\";\\r\\n\\r\\n/// @notice Library to make new borrow, extend/reduce exist borrows and repay to keep proper assets proportions\\r\\n/// @dev Swap through liquidator is still allowed to be able to get required profitToCover, but this amount is small\\r\\nlibrary BorrowLib {\\r\\n /// @notice prop0 + prop1\\r\\n uint constant public SUM_PROPORTIONS = 1e18;\\r\\n\\r\\n /// @notice Function {_rebalanceAssets} cannot be called recursively more than twice.\\r\\n /// Normally one call is enough.\\r\\n /// Firstly repay(requiredAmount0) is called below. There are two possible results:\\r\\n /// 1) requiredCost0 <= cost0\\r\\n /// 2) v.directDebt == 0\\r\\n /// There is SCB-818: there are two debts (big and small), on the first cycle we get amount less than expected\\r\\n /// because of debt gap. So, we need second cycle.\\r\\n uint constant public MAX_DEEP_RECURSION = 2;\\r\\n\\r\\n //region -------------------------------------------------- Data types\\r\\n struct PricesDecs {\\r\\n /// @notice Asset prices in USD, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice decs 10**decimals\\r\\n uint[] decs;\\r\\n }\\r\\n\\r\\n struct ConverterLiquidator {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n }\\r\\n\\r\\n struct RebalanceAssetsLocal {\\r\\n // ------- constant values\\r\\n address asset0;\\r\\n address asset1;\\r\\n /// @notice Proportion of {asset0}, > 0; proportion of {asset1} is SUM_PROPORTIONS - prop0\\r\\n uint prop0;\\r\\n /// @notice Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n uint threshold0;\\r\\n /// @ntoice Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n uint threshold1;\\r\\n\\r\\n PricesDecs pd;\\r\\n // ------- refreshable values\\r\\n\\r\\n // @notice Current balance of {asset0}\\r\\n uint amount0;\\r\\n // @notice Current balance of {asset1}\\r\\n uint amount1;\\r\\n\\r\\n /// @notice Borrowed amount of not-underlying\\r\\n uint directDebt;\\r\\n /// @notice Borrowed amount of underlying\\r\\n uint reverseDebt;\\r\\n\\r\\n uint addition0;\\r\\n }\\r\\n\\r\\n /// @notice Params required to borrow {assetB} under {assetA}\\r\\n struct RebalanceAssetsCore {\\r\\n ConverterLiquidator converterLiquidator;\\r\\n address assetA;\\r\\n address assetB;\\r\\n uint propA;\\r\\n uint propB;\\r\\n /// @notice {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n uint alpha18;\\r\\n /// @notice Min allowed amount of {assetA}-collateral, 0 - use default min value\\r\\n uint thresholdA;\\r\\n\\r\\n uint addonA;\\r\\n uint addonB;\\r\\n\\r\\n /// @notice Index of {assetA} in {prices} and {decs}\\r\\n uint indexA;\\r\\n /// @notice Index of {assetB} in {prices} and {decs}\\r\\n uint indexB;\\r\\n }\\r\\n\\r\\n struct OpenPosition2Local {\\r\\n uint collateral;\\r\\n uint toBorrow;\\r\\n uint cc;\\r\\n uint cb;\\r\\n uint c0;\\r\\n uint cb2;\\r\\n uint ca0;\\r\\n uint gamma18;\\r\\n uint pa2;\\r\\n uint pb2;\\r\\n bytes entryData;\\r\\n uint alpha18;\\r\\n }\\r\\n\\r\\n struct MakeBorrowToDepositLocal {\\r\\n uint[] prices;\\r\\n uint[] decs;\\r\\n uint cost0;\\r\\n uint cost1;\\r\\n uint prop1;\\r\\n bytes entryData;\\r\\n }\\r\\n //endregion -------------------------------------------------- Data types\\r\\n\\r\\n //region -------------------------------------------------- External functions\\r\\n /// @notice Set balances of {asset0} and {asset1} in proportions {prop0}:{prop1} using borrow/repay (no swaps)\\r\\n /// @param prop0 Proportion of {asset0}, > 0. Proportion of {asset1} is calculates as 1e18 - prop0\\r\\n /// @param threshold0 Min allowed amount of {asset0}-collateral, 0 - use default min value\\r\\n /// @param threshold1 Min allowed amount of {asset1}-collateral, 0 - use default min value\\r\\n /// @param addition0 Additional amount A0 of {asset0}.\\r\\n /// Balance0 = A0 + B0\\r\\n /// We need following balances in results: B0 : Balance1 === {proportion}:{100_000-proportion}\\r\\n function rebalanceAssets(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address asset0,\\r\\n address asset1,\\r\\n uint prop0,\\r\\n uint threshold0,\\r\\n uint threshold1,\\r\\n uint addition0\\r\\n ) external {\\r\\n // pool always have TWO assets, it's not allowed ot have only one asset\\r\\n // so, we assume that the proportions are in the range (0...1e18)\\r\\n require(prop0 != 0, AppErrors.ZERO_VALUE);\\r\\n require(prop0 < SUM_PROPORTIONS, AppErrors.TOO_HIGH);\\r\\n\\r\\n RebalanceAssetsLocal memory v;\\r\\n v.asset0 = asset0;\\r\\n v.asset1 = asset1;\\r\\n v.prop0 = prop0;\\r\\n v.threshold0 = threshold0;\\r\\n v.threshold1 = threshold1;\\r\\n v.addition0 = addition0;\\r\\n\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = asset0;\\r\\n tokens[1] = asset1;\\r\\n (v.pd.prices, v.pd.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n\\r\\n _refreshRebalance(v, ConverterLiquidator(converter_, liquidator_), MAX_DEEP_RECURSION);\\r\\n }\\r\\n\\r\\n /// @notice Convert {amount_} of underlying to two amounts: A0 (underlying) and A1 (not-underlying)\\r\\n /// Result proportions of A0 and A1 should match to {prop0} : 1e18-{prop0}\\r\\n /// The function is able to make new borrowing and/or close exist debts.\\r\\n /// @param amount_ Amount of underlying that is going to be deposited\\r\\n /// We assume here, that current balance >= the {amount_}\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @return tokenAmounts Result amounts [A0 (underlying), A1 (not-underlying)]\\r\\n function prepareToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n uint[2] memory amountsToDeposit;\\r\\n uint[2] memory balances = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), amount_), // We assume here, that current balance >= the {amount_}\\r\\n AppLib.balance(tokens_[1])\\r\\n ];\\r\\n\\r\\n // we assume here, that either direct OR reverse debts (amount > threshold) are possible but not both at the same time\\r\\n (uint debtReverse, ) = converter_.getDebtAmountCurrent(address(this), tokens_[1], tokens_[0], true);\\r\\n if (debtReverse > thresholds_[0]) {\\r\\n // case 1: reverse debt exists\\r\\n // case 1.1: amount to deposit exceeds exist debt.\\r\\n // Close the debt completely and than make either new direct OR reverse debt\\r\\n // case 1.2: amount to deposit is less than the exist debt.\\r\\n // Close the debt partially and make new reverse debt\\r\\n uint amountToRepay = amount_ > debtReverse ? debtReverse : amount_;\\r\\n ConverterStrategyBaseLib.closePosition(converter_, tokens_[1], tokens_[0], amountToRepay);\\r\\n amountsToDeposit = [\\r\\n AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]),\\r\\n AppLib.sub0(AppLib.balance(tokens_[1]), balances[1])\\r\\n ];\\r\\n } else {\\r\\n // case 2: no debts OR direct debt exists\\r\\n amountsToDeposit = [amount_, 0];\\r\\n }\\r\\n\\r\\n _makeBorrowToDeposit(converter_, amountsToDeposit, tokens_, thresholds_, prop0);\\r\\n\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.sub0(AppLib.balance(tokens_[0]), balances[0]);\\r\\n tokenAmounts[1] = AppLib.sub0(AppLib.balance(tokens_[1]), balances[1]);\\r\\n }\\r\\n //endregion -------------------------------------------------- External functions\\r\\n\\r\\n //region -------------------------------------------------- Implementation of prepareToDeposit\\r\\n /// @notice Make a direct or reverse borrow to make amounts_ fit to the given proportions.\\r\\n /// If one of available amounts is zero, we just need to make a borrow using second amount as amountIn.\\r\\n /// Otherwise, we need to calculate amountIn at first.\\r\\n /// @dev The purpose is to get the amounts in proper proportions: A:B = prop0:prop1.\\r\\n /// Suppose, amounts_[1] is not enough:\\r\\n /// [A1, B1] => [A2 + A3, B1], A2:B1 = prop0:prop1, A3 is amountIn for new borrow.\\r\\n /// Suppose, amounts_[0] is not enough:\\r\\n /// [A1, B1] => [A1, B2 + B3], A1:B2 = prop0:prop1, B3 is amountIn for new borrow.\\r\\n /// @param amounts_ Available amounts\\r\\n /// @param tokens_ [Underlying, not underlying]\\r\\n /// @param thresholds_ Thresholds for the given {tokens_}. Debts with amount-to-repay < threshold are ignored.\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n function _makeBorrowToDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint[2] memory amounts_,\\r\\n address[2] memory tokens_,\\r\\n uint[2] memory thresholds_,\\r\\n uint prop0\\r\\n ) internal {\\r\\n MakeBorrowToDepositLocal memory v;\\r\\n\\r\\n {\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokens_[0];\\r\\n tokens[1] = tokens_[1];\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(priceOracle, tokens, 2);\\r\\n }\\r\\n\\r\\n v.cost0 = amounts_[0] * v.prices[0] / v.decs[0];\\r\\n v.cost1 = amounts_[1] * v.prices[1] / v.decs[1];\\r\\n // we need: cost0/cost1 = prop0/prop1, and so cost0 * prop1 = cost1 * prop0\\r\\n v.prop1 = SUM_PROPORTIONS - prop0;\\r\\n\\r\\n if (v.cost0 * v.prop1 > v.cost1 * prop0) {\\r\\n // we need to make direct borrow\\r\\n uint cost0for1 = v.cost1 * prop0 / v.prop1; // a part of cost0 that is matched to cost1\\r\\n uint amountIn = (v.cost0 - cost0for1) * v.decs[0] / v.prices[0];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[0], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, prop0, v.prop1); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[0], tokens_[1], amountIn, thresholds_[0]);\\r\\n } else if (v.cost0 * v.prop1 < v.cost1 * prop0) {\\r\\n // we need to make reverse borrow\\r\\n uint cost1for0 = v.cost0 * v.prop1 / prop0; // a part of cost1 that is matched to cost0\\r\\n uint amountIn = (v.cost1 - cost1for0) * v.decs[1] / v.prices[1];\\r\\n\\r\\n AppLib.approveIfNeeded(tokens_[1], amountIn, address(converter_));\\r\\n v.entryData = abi.encode(1, v.prop1, prop0); // ENTRY_KIND_EXACT_PROPORTION_1\\r\\n ConverterStrategyBaseLib.openPosition(converter_, v.entryData, tokens_[1], tokens_[0], amountIn, thresholds_[1]);\\r\\n }\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Implementation of prepareToDeposit\\r\\n\\r\\n //region -------------------------------------------------- Internal helper functions\\r\\n\\r\\n /// @notice refresh state in {v} and call _rebalanceAssets()\\r\\n function _refreshRebalance(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n v.amount0 = IERC20(v.asset0).balanceOf(address(this));\\r\\n v.amount1 = IERC20(v.asset1).balanceOf(address(this));\\r\\n\\r\\n (v.directDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset0, v.asset1, true);\\r\\n (v.reverseDebt, ) = converterLiquidator.converter.getDebtAmountCurrent(address(this), v.asset1, v.asset0, true);\\r\\n\\r\\n _rebalanceAssets(v, converterLiquidator, repayAllowed);\\r\\n }\\r\\n\\r\\n /// @param repayAllowed Protection against recursion\\r\\n /// Assets can be rebalanced in two ways:\\r\\n /// 1) openPosition\\r\\n /// 2) repay + openPosition\\r\\n /// Only one repay is allowed.\\r\\n function _rebalanceAssets(\\r\\n RebalanceAssetsLocal memory v,\\r\\n ConverterLiquidator memory converterLiquidator,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n uint cost0 = v.amount0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n uint cost1 = v.amount1 * v.pd.prices[1] / v.pd.decs[1];\\r\\n uint costAddition0 = v.addition0 * v.pd.prices[0] / v.pd.decs[0];\\r\\n\\r\\n if (cost0 + cost1 > costAddition0) {\\r\\n uint totalCost = cost0 + cost1 - costAddition0;\\r\\n\\r\\n uint requiredCost0 = totalCost * v.prop0 / SUM_PROPORTIONS + costAddition0;\\r\\n uint requiredCost1 = totalCost * (SUM_PROPORTIONS - v.prop0) / SUM_PROPORTIONS;\\r\\n\\r\\n if (requiredCost0 > cost0) {\\r\\n // we need to increase amount of asset 0 and decrease amount of asset 1, so we need to borrow asset 0 (reverse)\\r\\n RebalanceAssetsCore memory c10 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset1,\\r\\n assetB: v.asset0,\\r\\n propA: SUM_PROPORTIONS - v.prop0,\\r\\n propB: v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[0] * v.pd.decs[1] / v.pd.prices[1] / v.pd.decs[0],\\r\\n thresholdA: v.threshold1,\\r\\n addonA: 0,\\r\\n addonB: v.addition0,\\r\\n indexA: 1,\\r\\n indexB: 0\\r\\n });\\r\\n\\r\\n if (v.directDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset1 is required\\r\\n uint requiredAmount0 = (requiredCost0 - cost0) * v.pd.decs[0] / v.pd.prices[0];\\r\\n rebalanceRepayBorrow(v, c10, requiredAmount0, v.directDebt, repayAllowed);\\r\\n } else {\\r\\n // new (or additional) borrow of asset 0 under asset 1 is required\\r\\n openPosition(c10, v.pd, v.amount1, v.amount0);\\r\\n }\\r\\n } else if (requiredCost0 < cost0) {\\r\\n RebalanceAssetsCore memory c01 = RebalanceAssetsCore({\\r\\n converterLiquidator: converterLiquidator,\\r\\n assetA: v.asset0,\\r\\n assetB: v.asset1,\\r\\n propA: v.prop0,\\r\\n propB: SUM_PROPORTIONS - v.prop0,\\r\\n alpha18: 1e18 * v.pd.prices[1] * v.pd.decs[0] / v.pd.prices[0] / v.pd.decs[1],\\r\\n thresholdA: v.threshold0,\\r\\n addonA: v.addition0,\\r\\n addonB: 0,\\r\\n indexA: 0,\\r\\n indexB: 1\\r\\n });\\r\\n // we need to decrease amount of asset 0 and increase amount of asset 1, so we need to borrow asset 1 (direct)\\r\\n if (v.reverseDebt >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // repay of v.asset0 is required\\r\\n // requiredCost0 < cost0 => requiredCost1 > cost1\\r\\n uint requiredAmount1 = (requiredCost1 - cost1) * v.pd.decs[1] / v.pd.prices[1];\\r\\n rebalanceRepayBorrow(v, c01, requiredAmount1, v.reverseDebt, repayAllowed);\\r\\n } else {\\r\\n // new or additional borrow of asset 1 under asset 0 is required\\r\\n openPosition(c01, v.pd, v.amount0, v.amount1);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // if costAddition0 exceeds cost0 + cost1, all amounts should be converted to asset 0\\r\\n // for simplicity, we don't make any swaps or borrows (amount addition0 is assumed to be small)\\r\\n // and just leave balances as is\\r\\n // as result, profit-to-cover will be reduced from costAddition0 to v.amount0\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Repay {amountDebtA} fully or partially to get at least {requiredAmountB} of collateral\\r\\n /// then try to rebalance once more\\r\\n /// @param requiredAmountB Amount of collateral that we need to receive after repay\\r\\n /// @param amountDebtA Total amount that is required to pay to close the debt\\r\\n function rebalanceRepayBorrow(\\r\\n RebalanceAssetsLocal memory v,\\r\\n RebalanceAssetsCore memory c,\\r\\n uint requiredAmountB,\\r\\n uint amountDebtA,\\r\\n uint repayAllowed\\r\\n ) internal {\\r\\n // repayAllowed cannot be zero here because of requires in _rebalanceAssets, but it's safer to check it once more\\r\\n require(repayAllowed != 0, AppErrors.TOO_DEEP_RECURSION_BORROW_LIB);\\r\\n\\r\\n // we need to get {requiredAmountB}\\r\\n // we don't know exact amount to repay\\r\\n // but we are sure that amount {requiredAmountB ===> requiredAmountA} would be more than required\\r\\n uint capRequiredAmountA = requiredAmountB * c.alpha18 / 1e18;\\r\\n uint amountToRepay = Math.min(capRequiredAmountA, amountDebtA);\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n ConverterStrategyBaseLib._repayDebt(c.converterLiquidator.converter, c.assetB, c.assetA, amountToRepay);\\r\\n _refreshRebalance(v, c.converterLiquidator, repayAllowed - 1);\\r\\n } // else the assets are already in proper proportions\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Internal helper functions\\r\\n\\r\\n //region -------------------------------------------------- Open position\\r\\n /// @notice borrow asset B under asset A. Result balances should be A0 + A1, B0 + B1\\r\\n /// Where (A1 : B1) == (propA : propB), A0 and B0 are equal to {c.addonA} and {c.addonB}\\r\\n /// @param balanceA_ Current balance of the collateral\\r\\n /// @param balanceB_ Current balance of the borrow asset\\r\\n function openPosition(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint balanceB_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n // if there are two not-zero addons, the caller should reduce balances before the call\\r\\n require(c.addonA == 0 || c.addonB == 0, AppErrors.INVALID_VALUE);\\r\\n\\r\\n // we are going to borrow B under A\\r\\n if (c.addonB != 0) {\\r\\n // B is underlying, so we are going to borrow underlying\\r\\n if (balanceB_ >= c.addonB) {\\r\\n // simple case - we already have required addon on the balance. Just keep it unused\\r\\n return _openPosition(c, balanceA_, balanceB_ - c.addonB);\\r\\n } else {\\r\\n // we need to get 1) (c.addonB + balanceB_) amount, so we will have required c.addonB\\r\\n // 2) leftovers of A and B should be allocated in required proportions\\r\\n // it's too hard to calculate correctly required to borrow amount in this case without changing TetuConverter\\r\\n // but we can assume here, that amount (c.addonB - balanceB_) is pretty small (it's profitToCover)\\r\\n // so, we can swap this required amount through liquidator at first\\r\\n // then use _openPosition to re-allocated rest amounts to proper proportions\\r\\n (uint decA,) = _makeLittleSwap(c, pd, balanceA_, c.addonB - balanceB_);\\r\\n return _openPosition(c, balanceA_ - decA, balanceB_);\\r\\n }\\r\\n } else if (c.addonA != 0) {\\r\\n // A is underlying, we need to put aside c.addonA and allocate leftovers in right proportions.\\r\\n // we are going to borrow B under asset A, so the case (balanceA_ < c.addonA) is not valid here\\r\\n require(balanceA_ >= c.addonA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n return _openPosition(c, balanceA_ - c.addonA, balanceB_);\\r\\n } else {\\r\\n // simple logic, no addons\\r\\n return _openPosition(c, balanceA_, balanceB_);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow asset B under asset A, result balances should have proportions: (propA : propB)\\r\\n function _openPosition(RebalanceAssetsCore memory c, uint balanceA_, uint balanceB_) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n uint untouchedAmountA;\\r\\n bytes memory entryData = abi.encode(1, c.propA, c.propB);\\r\\n\\r\\n if (balanceB_ != 0) {\\r\\n // we are going to use {balanceA_} as collateral\\r\\n // but there is some amount on {balanceB_}, so we need to keep corresponded part of {balanceA_} untouched\\r\\n untouchedAmountA = balanceB_ * c.alpha18 * c.propA / c.propB / 1e18;\\r\\n\\r\\n // we are going to borrow B under A, so balance A must be greater then balance B\\r\\n // otherwise the function is called incorrectly - probably we need to borrow A under B\\r\\n require(untouchedAmountA <= balanceA_, AppErrors.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n AppLib.approveIfNeeded(c.assetA, balanceA_ - untouchedAmountA, address(c.converterLiquidator.converter));\\r\\n\\r\\n return ConverterStrategyBaseLib.openPosition(\\r\\n c.converterLiquidator.converter,\\r\\n entryData,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n balanceA_ - untouchedAmountA,\\r\\n c.thresholdA\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Open position\\r\\n\\r\\n //region -------------------------------------------------- Little swap\\r\\n /// @notice Swap min amount of A to get {requiredAmountB}\\r\\n /// @return spentAmountIn how much the balance A has decreased\\r\\n /// @return receivedAmountOut how much the balance B has increased\\r\\n function _makeLittleSwap(\\r\\n RebalanceAssetsCore memory c,\\r\\n PricesDecs memory pd,\\r\\n uint balanceA_,\\r\\n uint requiredAmountB\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n uint amountInA = requiredAmountB * pd.prices[c.indexB] * pd.decs[c.indexA] / pd.prices[c.indexA] / pd.decs[c.indexB];\\r\\n // we can have some loss because of slippage\\r\\n // so, let's increase input amount a bit\\r\\n amountInA = amountInA * (100_000 + ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE) / 100_000;\\r\\n\\r\\n // in practice the addition is required to pay ProfitToCover\\r\\n // we assume, that total addition amount is small enough, much smaller then the total balance\\r\\n // otherwise something is wrong: we are going to pay ProfitToCover, but we don't have enough amount on the balances.\\r\\n require(balanceA_ > amountInA, AppErrors.NOT_ENOUGH_BALANCE);\\r\\n\\r\\n (spentAmountIn, receivedAmountOut) = ConverterStrategyBaseLib.liquidate(\\r\\n c.converterLiquidator.converter,\\r\\n c.converterLiquidator.liquidator,\\r\\n c.assetA,\\r\\n c.assetB,\\r\\n amountInA,\\r\\n ConverterStrategyBaseLib._ASSET_LIQUIDATION_SLIPPAGE,\\r\\n c.thresholdA,\\r\\n false\\r\\n );\\r\\n }\\r\\n\\r\\n //endregion -------------------------------------------------- Little swap\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x5a94be3da8739c31b91b0e4c6ca7860e96d052ef2d1975b63983e33eed33a8a8\",\"license\":\"BUSL-1.1\"},\"contracts/libs/ConverterEntryKinds.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\n/// @notice Utils and constants related to entryKind param of ITetuConverter.findBorrowStrategy\\r\\nlibrary ConverterEntryKinds {\\r\\n /// @notice Amount of collateral is fixed. Amount of borrow should be max possible.\\r\\n uint constant public ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0 = 0;\\r\\n\\r\\n /// @notice Split provided source amount S on two parts: C1 and C2 (C1 + C2 = S)\\r\\n /// C2 should be used as collateral to make a borrow B.\\r\\n /// Results amounts of C1 and B (both in terms of USD) must be in the given proportion\\r\\n uint constant public ENTRY_KIND_EXACT_PROPORTION_1 = 1;\\r\\n\\r\\n /// @notice Borrow given amount using min possible collateral\\r\\n uint constant public ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2 = 2;\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x4f4332c8be1be5fd85fef7c06795fc19957b35a4f2e3735fdd89c0906ddc923b\",\"license\":\"BUSL-1.1\"},\"contracts/libs/IterationPlanLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\nimport \\\"./AppLib.sol\\\";\\r\\n\\r\\n/// @notice Support of withdraw iteration plans\\r\\nlibrary IterationPlanLib {\\r\\n\\r\\n//region ------------------------------------------------ Constants\\r\\n /// @notice Swap collateral asset to get required amount-to-repay, then repay and get more collateral back.\\r\\n /// It tries to minimizes count of repay-operations.\\r\\n /// If there are no debts, swap leftovers to get required proportions of the asset.\\r\\n /// This mode is intended i.e. for \\\"withdraw all\\\"\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_REPAY = 0;\\r\\n\\r\\n /// @notice Repay available amount-to-repay, swap all or part of collateral to borrowed-asset, make one repay if needed.\\r\\n /// Swap + second repay tries to make asset balances to proportions required by the pool.\\r\\n /// Proportions are read from pool through IPoolProportionsProvider(this) and re-read after swapping.\\r\\n /// This mode is intended i.e. for rebalancing debts using single iteration.\\r\\n /// (uint256, uint256, uint256) - (entry kind, propNotUnderlying18, required-amount-to-reduce-the-debt)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_REPAY_SWAP_REPAY = 1;\\r\\n\\r\\n /// @notice Swap leftovers to required proportions, don't repay any debts\\r\\n /// (uint256, uint256) - (entry kind, propNotUnderlying18)\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The assets should be swapped to get following result proportions:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : (1e18 - propNotUnderlying18)\\r\\n /// Pass type(uint).max to read proportions from the pool.\\r\\n uint constant public PLAN_SWAP_ONLY = 2;\\r\\n//endregion ------------------------------------------------ Constants\\r\\n\\r\\n//region ------------------------------------------------ Data types\\r\\n /// @notice Set of parameters required to liquidation through aggregators\\r\\n struct SwapRepayPlanParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n\\r\\n /// @notice Assets used by depositor stored as following way: [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n\\r\\n /// @notice Liquidation thresholds for the {tokens}\\r\\n uint[] liquidationThresholds;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n /// @notice Plan kind extracted from entry data, see {IterationPlanKinds}\\r\\n uint planKind;\\r\\n\\r\\n /// @notice Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n uint propNotUnderlying18;\\r\\n\\r\\n /// @notice proportions should be taken from the pool and re-read from the pool after each swap\\r\\n bool usePoolProportions;\\r\\n\\r\\n /// @notice \\\"required-amount-to-reduce-debt\\\" in the case of REPAY-SWAP-REPAY, zero in other cases\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n struct GetIterationPlanLocal {\\r\\n /// @notice Underlying balance\\r\\n uint assetBalance;\\r\\n /// @notice Not-underlying balance\\r\\n uint tokenBalance;\\r\\n\\r\\n uint totalDebt;\\r\\n uint totalCollateral;\\r\\n\\r\\n uint debtReverse;\\r\\n uint collateralReverse;\\r\\n\\r\\n address asset;\\r\\n address token;\\r\\n\\r\\n bool swapLeftoversNeeded;\\r\\n }\\r\\n\\r\\n struct EstimateSwapAmountForRepaySwapRepayLocal {\\r\\n uint x;\\r\\n uint y;\\r\\n uint bA1;\\r\\n uint bB1;\\r\\n uint alpha;\\r\\n uint swapRatio;\\r\\n uint aB3;\\r\\n uint cA1;\\r\\n uint cB1;\\r\\n uint aA2;\\r\\n uint aB2;\\r\\n }\\r\\n//endregion ------------------------------------------------ Data types\\r\\n\\r\\n /// @notice Decode entryData, extract first uint - entry kind\\r\\n /// Valid values of entry kinds are given by ENTRY_KIND_XXX constants above\\r\\n function getEntryKind(bytes memory entryData_) internal pure returns (uint) {\\r\\n if (entryData_.length == 0) {\\r\\n return PLAN_SWAP_REPAY;\\r\\n }\\r\\n return abi.decode(entryData_, (uint));\\r\\n }\\r\\n\\r\\n//region ------------------------------------------------ Build plan\\r\\n /// @notice Build plan to make single iteration of withdraw according to the selected plan\\r\\n /// The goal is to withdraw {requestedAmount} and receive {asset}:{token} in proper proportions on the balance\\r\\n /// @param converterLiquidator [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens List of the pool tokens. One of them is underlying and one of then is not-underlying\\r\\n /// that we are going to withdraw\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}. If amount is less then the threshold,\\r\\n /// we cannot swap it.\\r\\n /// @param prices Prices of the {tokens}, decimals 18, [$/token]\\r\\n /// @param decs 10**decimal for each token of the {tokens}\\r\\n /// @param balanceAdditions Amounts that will be added to the current balances of the {tokens}\\r\\n /// to the moment of the plan execution\\r\\n /// @param packedData Several values packed to fixed-size array (to reduce number of params)\\r\\n /// 0: usePoolProportions: 1 - read proportions from the pool through IPoolProportionsProvider(this)\\r\\n /// 1: planKind: selected plan, one of PLAN_XXX\\r\\n /// 2: propNotUnderlying18: value of not-underlying proportion [0..1e18] if usePoolProportions == 0\\r\\n /// 3: requestedBalance: total amount that should be withdrawn, it can be type(uint).max\\r\\n /// 4: indexAsset: index of the underlying in {tokens} array\\r\\n /// 5: indexToken: index of the token in {tokens} array. We are going to withdraw the token and convert it to the asset\\r\\n /// 6: entryDataParam: required-amount-to-reduce-debt in REPAY-SWAP-REPAY case; zero in other cases\\r\\n function buildIterationPlan(\\r\\n address[2] memory converterLiquidator,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint[] memory balanceAdditions,\\r\\n uint[7] memory packedData\\r\\n ) external returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n return _buildIterationPlan(\\r\\n SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: balanceAdditions,\\r\\n planKind: packedData[1],\\r\\n propNotUnderlying18: packedData[2],\\r\\n usePoolProportions: packedData[0] != 0,\\r\\n entryDataParam: packedData[6]\\r\\n }),\\r\\n packedData[3],\\r\\n packedData[4],\\r\\n packedData[5]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Generate plan for next withdraw iteration. We can do only one swap per iteration.\\r\\n /// In general, we cam make 1) single swap (direct or reverse) and 2) repay\\r\\n /// Swap is required to get required repay-amount OR to swap leftovers on final iteration.\\r\\n /// @param requestedBalance Amount of underlying that we need to have on balance after executing the plan.\\r\\n /// @param indexAsset Index of the underlying in {p.tokens} array\\r\\n /// @param indexToken Index of the not-underlying in {p.tokens} array\\r\\n /// @return indexToSwapPlus1 1-based index of the token to be swapped; 0 means swap is not required.\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap\\r\\n /// @return indexToRepayPlus1 1-based index of the token that should be used to repay borrow in converter.\\r\\n /// 0 - no repay is required - it means that this is a last step with swapping leftovers.\\r\\n function _buildIterationPlan(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint requestedBalance,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n GetIterationPlanLocal memory v;\\r\\n v.asset = p.tokens[indexAsset];\\r\\n v.token = p.tokens[indexToken];\\r\\n\\r\\n v.assetBalance = IERC20(v.asset).balanceOf(address(this)) + p.balanceAdditions[indexAsset];\\r\\n v.tokenBalance = IERC20(p.tokens[indexToken]).balanceOf(address(this)) + p.balanceAdditions[indexToken];\\r\\n\\r\\n if (p.planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n uint requestedAmount = requestedBalance == type(uint).max\\r\\n ? type(uint).max\\r\\n : AppLib.sub0(requestedBalance, v.assetBalance);\\r\\n\\r\\n if (requestedAmount < p.liquidationThresholds[indexAsset]) {\\r\\n // we don't need to repay any debts anymore, but we should swap leftovers\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // we need to increase balance on the following amount: requestedAmount - v.balance;\\r\\n // we can have two possible borrows:\\r\\n // 1) direct (p.tokens[INDEX_ASSET] => tokens[i]) and 2) reverse (tokens[i] => p.tokens[INDEX_ASSET])\\r\\n // normally we can have only one of them, not both..\\r\\n // but better to take into account possibility to have two debts simultaneously\\r\\n\\r\\n // reverse debt\\r\\n (v.debtReverse, v.collateralReverse) = p.converter.getDebtAmountCurrent(address(this), v.token, v.asset, true);\\r\\n if (v.debtReverse < AppLib.DUST_AMOUNT_TOKENS) { // there is reverse debt or the reverse debt is dust debt\\r\\n // direct debt\\r\\n (v.totalDebt, v.totalCollateral) = p.converter.getDebtAmountCurrent(address(this), v.asset, v.token, true);\\r\\n\\r\\n if (v.totalDebt < AppLib.DUST_AMOUNT_TOKENS) { // there is direct debt or the direct debt is dust debt\\r\\n // This is final iteration - we need to swap leftovers and get amounts on balance in proper proportions.\\r\\n // The leftovers should be swapped to get following result proportions of the assets:\\r\\n // underlying : not-underlying === 1e18 - propNotUnderlying18 : propNotUnderlying18\\r\\n v.swapLeftoversNeeded = true;\\r\\n } else {\\r\\n // repay direct debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.assetBalance, v.tokenBalance],\\r\\n [indexAsset, indexToken],\\r\\n p.propNotUnderlying18,\\r\\n [v.totalCollateral, v.totalDebt],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount,\\r\\n p,\\r\\n v.totalCollateral,\\r\\n v.totalDebt,\\r\\n indexAsset,\\r\\n indexToken,\\r\\n v.assetBalance,\\r\\n v.tokenBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // repay reverse debt\\r\\n if (p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY) {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanRepaySwapRepay(\\r\\n p,\\r\\n [v.tokenBalance, v.assetBalance],\\r\\n [indexToken, indexAsset],\\r\\n 1e18 - p.propNotUnderlying18,\\r\\n [v.collateralReverse, v.debtReverse],\\r\\n p.entryDataParam\\r\\n );\\r\\n } else {\\r\\n (indexToSwapPlus1, amountToSwap, indexToRepayPlus1) = _buildPlanForSellAndRepay(\\r\\n requestedAmount == type(uint).max\\r\\n ? type(uint).max\\r\\n : requestedAmount * p.prices[indexAsset] * p.decs[indexToken] / p.prices[indexToken] / p.decs[indexAsset],\\r\\n p,\\r\\n v.collateralReverse,\\r\\n v.debtReverse,\\r\\n indexToken,\\r\\n indexAsset,\\r\\n v.tokenBalance,\\r\\n v.assetBalance\\r\\n );\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (v.swapLeftoversNeeded) {\\r\\n (indexToSwapPlus1, amountToSwap) = _buildPlanForLeftovers(p, v.assetBalance, v.tokenBalance, indexAsset, indexToken, p.propNotUnderlying18);\\r\\n }\\r\\n\\r\\n return (indexToSwapPlus1, amountToSwap, indexToRepayPlus1);\\r\\n }\\r\\n\\r\\n /// @notice Repay B, get collateral A, then swap A => B, [make one more repay B] => get A:B in required proportions\\r\\n /// @param balancesAB [balanceA, balanceB]\\r\\n /// @param idxAB [indexA, indexB]\\r\\n /// @param totalAB [totalCollateralA, totalBorrowB]\\r\\n /// @param requiredAmountToReduceDebt If not zero: we are going to make repay-swap-repay to reduce total\\r\\n /// debt on the given amount. So, if possible it worth to make swap in such a way as to reduce\\r\\n /// the amount of debt by the given amount.\\r\\n function _buildPlanRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory idxAB,\\r\\n uint propB,\\r\\n uint[2] memory totalAB,\\r\\n uint requiredAmountToReduceDebt\\r\\n ) internal returns (\\r\\n uint indexToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexToRepayPlus1\\r\\n ) {\\r\\n // use all available tokenB to repay debt and receive as much as possible tokenA\\r\\n uint amountToRepay = Math.min(balancesAB[1], totalAB[1]);\\r\\n\\r\\n uint collateralAmount;\\r\\n if (amountToRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n uint swappedAmountOut;\\r\\n //\\r\\n (collateralAmount, swappedAmountOut) = p.converter.quoteRepay(address(this), p.tokens[idxAB[0]], p.tokens[idxAB[1]], amountToRepay);\\r\\n if (collateralAmount > swappedAmountOut) { // SCB-789\\r\\n collateralAmount -= swappedAmountOut;\\r\\n }\\r\\n } else {\\r\\n amountToRepay = 0;\\r\\n }\\r\\n\\r\\n // swap A to B: full or partial\\r\\n // SCB-876: swap B to A are also possible here\\r\\n bool swapB;\\r\\n (amountToSwap, swapB) = estimateSwapAmountForRepaySwapRepay(\\r\\n p,\\r\\n [balancesAB[0], balancesAB[1]],\\r\\n [idxAB[0], idxAB[1]],\\r\\n propB,\\r\\n totalAB[0],\\r\\n totalAB[1],\\r\\n collateralAmount,\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (swapB) {\\r\\n // edge case: swap B => A; for simplicity, we don't take into account requiredAmountToReduceDebt\\r\\n return (idxAB[1] + 1, amountToSwap, idxAB[1] + 1);\\r\\n } else {\\r\\n // swap A => B\\r\\n if (requiredAmountToReduceDebt != 0) {\\r\\n // probably it worth to increase amount to swap?\\r\\n uint requiredAmountToSwap = requiredAmountToReduceDebt * p.prices[idxAB[1]] * p.decs[idxAB[0]] / p.prices[idxAB[0]] / p.decs[idxAB[1]];\\r\\n amountToSwap = Math.max(amountToSwap, requiredAmountToSwap);\\r\\n amountToSwap = Math.min(amountToSwap, balancesAB[0] + collateralAmount);\\r\\n }\\r\\n\\r\\n return (idxAB[0] + 1, amountToSwap, idxAB[1] + 1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Estimate swap amount for iteration \\\"repay-swap-repay\\\"\\r\\n /// The iteration should give us amounts of assets in required proportions.\\r\\n /// There are two cases here: full swap and partial swap. Second repay is not required if the swap is partial.\\r\\n /// @param collateralA Estimated value of collateral A received after repay balanceB\\r\\n /// @return amountToSwap Amount to be swapped\\r\\n /// @return swapB False: swap A => B; True: swap B => A\\r\\n function estimateSwapAmountForRepaySwapRepay(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint[2] memory balancesAB,\\r\\n uint[2] memory indicesAB,\\r\\n uint propB,\\r\\n uint totalCollateralA,\\r\\n uint totalBorrowB,\\r\\n uint collateralA,\\r\\n uint amountToRepayB\\r\\n ) internal pure returns(uint amountToSwap, bool swapB) {\\r\\n // N - number of the state\\r\\n // bAN, bBN - balances of A and B; aAN, aBN - amounts of A and B; cAN, cBN - collateral/borrow amounts of A/B\\r\\n // alpha ~ cAN/cBN - estimated ratio of collateral/borrow\\r\\n // s = swap ratio, aA is swapped to aB, so aA = s * aB\\r\\n // g = split ratio, bA1 is divided on two parts: bA1 * gamma, bA1 * (1 - gamma). First part is swapped.\\r\\n // X = proportion of A, Y = proportion of B\\r\\n\\r\\n // Formulas\\r\\n // aB3 = (x * bB2 - y * bA2) / (alpha * y + x)\\r\\n // gamma = (y * bA1 - x * bB1) / (bA1 * (x * s + y))\\r\\n\\r\\n // There are following stages:\\r\\n // 0. init (we have at least not zero amount of B and not zero debt of B)\\r\\n // 1. repay 1 (repay all available amount of B OR all available debt)\\r\\n // 2. swap (swap A fully or partially to B)\\r\\n // 3. repay 2 (optional: we need this stage if full swap produces amount of B that is <= available debt)\\r\\n // 4. final (we have assets in right proportion on the balance)\\r\\n EstimateSwapAmountForRepaySwapRepayLocal memory v;\\r\\n v.x = 1e18 - propB;\\r\\n v.y = propB;\\r\\n// 1. repay 1\\r\\n // convert amounts A, amounts B to cost A, cost B in USD\\r\\n v.bA1 = (balancesAB[0] + collateralA) * p.prices[indicesAB[0]] / p.decs[indicesAB[0]];\\r\\n v.bB1 = (balancesAB[1] - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.cB1 = (totalBorrowB - amountToRepayB) * p.prices[indicesAB[1]] / p.decs[indicesAB[1]];\\r\\n v.alpha = 1e18 * totalCollateralA * p.prices[indicesAB[0]] * p.decs[indicesAB[1]]\\r\\n / p.decs[indicesAB[0]] / p.prices[indicesAB[1]] / totalBorrowB; // (!) approx estimation\\r\\n\\r\\n// 2. full swap\\r\\n v.aA2 = v.bA1;\\r\\n v.swapRatio = 1e18; // we assume swap ratio 1:1\\r\\n\\r\\n// 3. repay 2\\r\\n // aB3 = (x * bB2 - Y * bA2) / (alpha * y + x)\\r\\n v.aB3 = (\\r\\n v.x * (v.bB1 + v.aA2 * v.swapRatio / 1e18) // bB2 = v.bB1 + v.aA2 * v.s / 1e18\\r\\n - v.y * (v.bA1 - v.aA2) // bA2 = v.bA1 - v.aA2;\\r\\n ) / (v.y * v.alpha / 1e18 + v.x);\\r\\n\\r\\n if (v.aB3 > v.cB1) {\\r\\n if (v.y * v.bA1 >= v.x * v.bB1) {\\r\\n // there is not enough debt to make second repay\\r\\n // we need to make partial swap and receive assets in right proportions in result\\r\\n // v.gamma = 1e18 * (v.y * v.bA1 - v.x * v.bB1) / (v.bA1 * (v.x * v.s / 1e18 + v.y));\\r\\n v.aA2 = (v.y * v.bA1 - v.x * v.bB1) / (v.x * v.swapRatio / 1e18 + v.y);\\r\\n } else {\\r\\n // scb-867: edge case, we need to make swap B => A\\r\\n v.aB2 = (v.x * v.bB1 - v.y * v.bA1) / (v.x * v.swapRatio / 1e18 + v.y) /* * 1e18 / v.swapRatio */ ;\\r\\n swapB = true;\\r\\n }\\r\\n }\\r\\n\\r\\n return swapB\\r\\n ? (v.aB2 * p.decs[indicesAB[1]] / p.prices[indicesAB[1]], true) // edge case: swap B => A\\r\\n : (v.aA2 * p.decs[indicesAB[0]] / p.prices[indicesAB[0]], false); // normal case: swap A => B\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap leftovers to required proportion\\r\\n /// @param balanceA Balance of token A, i.e. underlying\\r\\n /// @param balanceB Balance of token B, i.e. not-underlying\\r\\n /// @param indexA Index of the token A, i.e. underlying, in {p.prices} and {p.decs}\\r\\n /// @param indexB Index of the token B, i.e. not-underlying, in {p.prices} and {p.decs}\\r\\n /// @param propB Required proportion of TokenB [0..1e18]. Proportion of token A is (1e18-propB)\\r\\n /// @return indexTokenToSwapPlus1 Index of the token to be swapped. 0 - no swap is required\\r\\n /// @return amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n function _buildPlanForLeftovers(\\r\\n SwapRepayPlanParams memory p,\\r\\n uint balanceA,\\r\\n uint balanceB,\\r\\n uint indexA,\\r\\n uint indexB,\\r\\n uint propB\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n (uint targetA, uint targetB) = _getTargetAmounts(p.prices, p.decs, balanceA, balanceB, propB, indexA, indexB);\\r\\n if (balanceA < targetA) {\\r\\n // we need to swap not-underlying to underlying\\r\\n if (balanceB - targetB > p.liquidationThresholds[indexB]) {\\r\\n amountToSwap = balanceB - targetB;\\r\\n indexTokenToSwapPlus1 = indexB + 1;\\r\\n }\\r\\n } else {\\r\\n // we need to swap underlying to not-underlying\\r\\n if (balanceA - targetA > p.liquidationThresholds[indexA]) {\\r\\n amountToSwap = balanceA - targetA;\\r\\n indexTokenToSwapPlus1 = indexA + 1;\\r\\n }\\r\\n }\\r\\n return (indexTokenToSwapPlus1, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Prepare a plan to swap some amount of collateral to get required repay-amount and make repaying\\r\\n /// 1) Sell collateral-asset to get missed amount-to-repay 2) make repay and get more collateral back\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount.\\r\\n /// @param totalCollateral Total amount of collateral used in the borrow\\r\\n /// @param totalDebt Total amount of debt that should be repaid to receive {totalCollateral}\\r\\n /// @param indexCollateral Index of collateral asset in {p.prices}, {p.decs}\\r\\n /// @param indexBorrow Index of borrow asset in {p.prices}, {p.decs}\\r\\n /// @param balanceCollateral Current balance of the collateral asset\\r\\n /// @param balanceBorrow Current balance of the borrowed asset\\r\\n /// @param indexTokenToSwapPlus1 1-based index of the token to be swapped. Swap of amount of collateral asset can be required\\r\\n /// to receive missed amount-to-repay. 0 - no swap is required\\r\\n /// @param amountToSwap Amount to be swapped. 0 - no swap is required\\r\\n /// @param indexRepayTokenPlus1 1-based index of the token to be repaied. 0 - no repaying is required\\r\\n function _buildPlanForSellAndRepay(\\r\\n uint requestedAmount,\\r\\n SwapRepayPlanParams memory p,\\r\\n uint totalCollateral,\\r\\n uint totalDebt,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow\\r\\n ) internal pure returns (\\r\\n uint indexTokenToSwapPlus1,\\r\\n uint amountToSwap,\\r\\n uint indexRepayTokenPlus1\\r\\n ) {\\r\\n // what amount of collateral we should sell to get required amount-to-pay to pay the debt\\r\\n uint toSell = _getAmountToSell(\\r\\n requestedAmount,\\r\\n totalDebt,\\r\\n totalCollateral,\\r\\n p.prices,\\r\\n p.decs,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n balanceBorrow\\r\\n );\\r\\n\\r\\n // convert {toSell} amount of underlying to token\\r\\n if (toSell != 0 && balanceCollateral != 0) {\\r\\n toSell = Math.min(toSell, balanceCollateral);\\r\\n uint threshold = p.liquidationThresholds[indexCollateral];\\r\\n if (toSell > threshold) {\\r\\n amountToSwap = toSell;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n } else {\\r\\n // we need to sell amount less than the threshold, it's not allowed\\r\\n // but it's dangerous to just ignore the selling because there is a chance to have error 35\\r\\n // (There is a debt $3.29, we make repay $3.27 => error 35)\\r\\n // it would be safer to sell a bit more amount if it's possible\\r\\n if (balanceCollateral >= threshold + 1) {\\r\\n amountToSwap = threshold + 1;\\r\\n indexTokenToSwapPlus1 = indexCollateral + 1;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (indexTokenToSwapPlus1, amountToSwap, indexBorrow + 1);\\r\\n }\\r\\n\\r\\n /// @notice Calculate what balances of underlying and not-underlying we need to fit {propNotUnderlying18}\\r\\n /// @param prices Prices of underlying and not underlying\\r\\n /// @param decs 10**decimals for underlying and not underlying\\r\\n /// @param assetBalance Current balance of underlying\\r\\n /// @param tokenBalance Current balance of not-underlying\\r\\n /// @param propNotUnderlying18 Required proportion of not-underlying [0..1e18]\\r\\n /// Proportion of underlying would be (1e18 - propNotUnderlying18)\\r\\n /// @param targetAssets What result balance of underlying is required to fit to required proportions\\r\\n /// @param targetTokens What result balance of not-underlying is required to fit to required proportions\\r\\n function _getTargetAmounts(\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint assetBalance,\\r\\n uint tokenBalance,\\r\\n uint propNotUnderlying18,\\r\\n uint indexAsset,\\r\\n uint indexToken\\r\\n ) internal pure returns (\\r\\n uint targetAssets,\\r\\n uint targetTokens\\r\\n ) {\\r\\n uint costAssets = assetBalance * prices[indexAsset] / decs[indexAsset];\\r\\n uint costTokens = tokenBalance * prices[indexToken] / decs[indexToken];\\r\\n targetTokens = propNotUnderlying18 == 0\\r\\n ? 0\\r\\n : ((costAssets + costTokens) * propNotUnderlying18 / 1e18);\\r\\n targetAssets = ((costAssets + costTokens) - targetTokens) * decs[indexAsset] / prices[indexAsset];\\r\\n targetTokens = targetTokens * decs[indexToken] / prices[indexToken];\\r\\n }\\r\\n\\r\\n /// @notice What amount of collateral should be sold to pay the debt and receive {requestedAmount}\\r\\n /// @dev It doesn't allow to sell more than the amount of total debt in the borrow\\r\\n /// @param requestedAmount We need to increase balance (of collateral asset) on this amount\\r\\n /// @param totalDebt Total debt of the borrow in terms of borrow asset\\r\\n /// @param totalCollateral Total collateral of the borrow in terms of collateral asset\\r\\n /// @param prices Cost of $1 in terms of the asset, decimals 18\\r\\n /// @param decs 10**decimals for each asset\\r\\n /// @param indexCollateral Index of the collateral asset in {prices} and {decs}\\r\\n /// @param indexBorrowAsset Index of the borrow asset in {prices} and {decs}\\r\\n /// @param balanceBorrowAsset Available balance of the borrow asset, it will be used to cover the debt\\r\\n /// @return amountOut Amount of collateral-asset that should be sold\\r\\n function _getAmountToSell(\\r\\n uint requestedAmount,\\r\\n uint totalDebt,\\r\\n uint totalCollateral,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n uint indexCollateral,\\r\\n uint indexBorrowAsset,\\r\\n uint balanceBorrowAsset\\r\\n ) internal pure returns (\\r\\n uint amountOut\\r\\n ) {\\r\\n if (totalDebt != 0) {\\r\\n if (balanceBorrowAsset != 0) {\\r\\n // there is some borrow asset on balance\\r\\n // it will be used to cover the debt\\r\\n // let's reduce the size of totalDebt/Collateral to exclude balanceBorrowAsset\\r\\n uint sub = Math.min(balanceBorrowAsset, totalDebt);\\r\\n totalCollateral -= totalCollateral * sub / totalDebt;\\r\\n totalDebt -= sub;\\r\\n }\\r\\n\\r\\n // for definiteness: usdc - collateral asset, dai - borrow asset\\r\\n // Pc = price of the USDC, Pb = price of the DAI, alpha = Pc / Pb [DAI / USDC]\\r\\n // S [USDC] - amount to sell, R [DAI] = alpha * S - amount to repay\\r\\n // After repaying R we get: alpha * S * C / R\\r\\n // Balance should be increased on: requestedAmount = alpha * S * C / R - S\\r\\n // So, we should sell: S = requestedAmount / (alpha * C / R - 1))\\r\\n // We can lost some amount on liquidation of S => R, so we need to use some gap = {GAP_AMOUNT_TO_SELL}\\r\\n // Same formula: S * h = S + requestedAmount, where h = health factor => s = requestedAmount / (h - 1)\\r\\n // h = alpha * C / R\\r\\n uint alpha18 = prices[indexCollateral] * decs[indexBorrowAsset] * 1e18\\r\\n / prices[indexBorrowAsset] / decs[indexCollateral];\\r\\n\\r\\n // if totalCollateral is zero (liquidation happens) we will have zero amount (the debt shouldn't be paid)\\r\\n amountOut = totalDebt != 0 && alpha18 * totalCollateral / totalDebt > 1e18\\r\\n ? Math.min(requestedAmount, totalCollateral) * 1e18 / (alpha18 * totalCollateral / totalDebt - 1e18)\\r\\n : 0;\\r\\n\\r\\n if (amountOut != 0) {\\r\\n // we shouldn't try to sell amount greater than amount of totalDebt in terms of collateral asset\\r\\n // but we always asks +1% because liquidation results can be different a bit from expected\\r\\n amountOut = (AppLib.GAP_CONVERSION + AppLib.DENOMINATOR) * Math.min(amountOut, totalDebt * 1e18 / alpha18) / AppLib.DENOMINATOR;\\r\\n }\\r\\n }\\r\\n\\r\\n return amountOut;\\r\\n }\\r\\n//endregion ------------------------------------------------ Build plan\\r\\n}\\r\\n\",\"keccak256\":\"0xbe94b0f9bfed116a0dd0fe1c212203b58d40d9a81416116d63fd07669f708596\",\"license\":\"BUSL-1.1\"},\"contracts/libs/TokenAmountsLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./AppErrors.sol\\\";\\r\\n\\r\\n/// @title Library for clearing / joining token addresses & amounts arrays\\r\\n/// @author bogdoslav\\r\\nlibrary TokenAmountsLib {\\r\\n /// @notice Version of the contract\\r\\n /// @dev Should be incremented when contract changed\\r\\n string internal constant TOKEN_AMOUNTS_LIB_VERSION = \\\"1.0.1\\\";\\r\\n\\r\\n function uncheckedInc(uint i) internal pure returns (uint) {\\r\\n unchecked {\\r\\n return i + 1;\\r\\n }\\r\\n }\\r\\n\\r\\n function filterZeroAmounts(\\r\\n address[] memory tokens,\\r\\n uint[] memory amounts\\r\\n ) internal pure returns (\\r\\n address[] memory t,\\r\\n uint[] memory a\\r\\n ) {\\r\\n require(tokens.length == amounts.length, AppErrors.INCORRECT_LENGTHS);\\r\\n uint len2 = 0;\\r\\n uint len = tokens.length;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n if (amounts[i] != 0) len2++;\\r\\n }\\r\\n\\r\\n t = new address[](len2);\\r\\n a = new uint[](len2);\\r\\n\\r\\n uint j = 0;\\r\\n for (uint i = 0; i < len; i++) {\\r\\n uint amount = amounts[i];\\r\\n if (amount != 0) {\\r\\n t[j] = tokens[i];\\r\\n a[j] = amount;\\r\\n j++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice unites three arrays to single array without duplicates, amounts are sum, zero amounts are allowed\\r\\n function combineArrays(\\r\\n address[] memory tokens0,\\r\\n uint[] memory amounts0,\\r\\n address[] memory tokens1,\\r\\n uint[] memory amounts1,\\r\\n address[] memory tokens2,\\r\\n uint[] memory amounts2\\r\\n ) internal pure returns (\\r\\n address[] memory allTokens,\\r\\n uint[] memory allAmounts\\r\\n ) {\\r\\n uint[] memory lens = new uint[](3);\\r\\n lens[0] = tokens0.length;\\r\\n lens[1] = tokens1.length;\\r\\n lens[2] = tokens2.length;\\r\\n\\r\\n require(\\r\\n lens[0] == amounts0.length && lens[1] == amounts1.length && lens[2] == amounts2.length,\\r\\n AppErrors.INCORRECT_LENGTHS\\r\\n );\\r\\n\\r\\n uint maxLength = lens[0] + lens[1] + lens[2];\\r\\n address[] memory tokensOut = new address[](maxLength);\\r\\n uint[] memory amountsOut = new uint[](maxLength);\\r\\n uint unitedLength;\\r\\n\\r\\n for (uint step; step < 3; ++step) {\\r\\n uint[] memory amounts = step == 0\\r\\n ? amounts0\\r\\n : (step == 1\\r\\n ? amounts1\\r\\n : amounts2);\\r\\n address[] memory tokens = step == 0\\r\\n ? tokens0\\r\\n : (step == 1\\r\\n ? tokens1\\r\\n : tokens2);\\r\\n for (uint i1 = 0; i1 < lens[step]; i1++) {\\r\\n uint amount1 = amounts[i1];\\r\\n address token1 = tokens[i1];\\r\\n bool united = false;\\r\\n\\r\\n for (uint i = 0; i < unitedLength; i++) {\\r\\n if (token1 == tokensOut[i]) {\\r\\n amountsOut[i] += amount1;\\r\\n united = true;\\r\\n break;\\r\\n }\\r\\n }\\r\\n\\r\\n if (!united) {\\r\\n tokensOut[unitedLength] = token1;\\r\\n amountsOut[unitedLength] = amount1;\\r\\n unitedLength++;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // copy united tokens to result array\\r\\n allTokens = new address[](unitedLength);\\r\\n allAmounts = new uint[](unitedLength);\\r\\n for (uint i; i < unitedLength; i++) {\\r\\n allTokens[i] = tokensOut[i];\\r\\n allAmounts[i] = amountsOut[i];\\r\\n }\\r\\n\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0xb3adb8a53441362b47b3bf5c0c7181f7c1652de7dde3df4fb765e8484447d074\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../libs/IterationPlanLib.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\nlibrary ConverterStrategyBaseLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region--------------------------------------------------- Data types\\r\\n\\r\\n /// @notice Local vars for {_recycle}, workaround for stack too deep\\r\\n struct RecycleLocalParams {\\r\\n /// @notice Compound amount + Performance amount\\r\\n uint amountCP;\\r\\n /// @notice Amount to compound\\r\\n uint amountC;\\r\\n /// @notice Amount to send to performance and insurance\\r\\n uint amountP;\\r\\n /// @notice Amount to forwarder + amount to compound\\r\\n uint amountFC;\\r\\n address rewardToken;\\r\\n uint len;\\r\\n uint receivedAmountOut;\\r\\n }\\r\\n\\r\\n struct OpenPositionLocal {\\r\\n uint entryKind;\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n }\\r\\n\\r\\n struct OpenPositionEntryKind1Local {\\r\\n address[] converters;\\r\\n uint[] collateralsRequired;\\r\\n uint[] amountsToBorrow;\\r\\n uint collateral;\\r\\n uint amountToBorrow;\\r\\n uint c1;\\r\\n uint c3;\\r\\n uint alpha;\\r\\n }\\r\\n\\r\\n struct CloseDebtsForRequiredAmountLocal {\\r\\n address asset;\\r\\n uint balanceAsset;\\r\\n uint balanceToken;\\r\\n\\r\\n uint newBalanceAsset;\\r\\n uint newBalanceToken;\\r\\n\\r\\n uint idxToSwap1;\\r\\n uint amountToSwap;\\r\\n uint idxToRepay1;\\r\\n\\r\\n /// @notice Cost of $1 in terms of the assets, decimals 18\\r\\n uint[] prices;\\r\\n /// @notice 10**decimal for the assets\\r\\n uint[] decs;\\r\\n\\r\\n /// @notice Amounts that will be received on balance before execution of the plan.\\r\\n uint[] balanceAdditions;\\r\\n\\r\\n bool exitLoop;\\r\\n }\\r\\n\\r\\n struct DataSetLocal {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n /// @notice Tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Index of the main asset in {tokens}\\r\\n uint indexAsset;\\r\\n /// @notice Length of {tokens}\\r\\n uint len;\\r\\n }\\r\\n\\r\\n struct RecycleLocal {\\r\\n address asset;\\r\\n address splitter;\\r\\n address vault;\\r\\n address insurance;\\r\\n int debtToInsuranceCurrent;\\r\\n int debtToInsuranceUpdated;\\r\\n uint toPerf;\\r\\n uint toInsurance;\\r\\n uint performanceFeeEffective;\\r\\n uint effectivePerformanceFeeRatio;\\r\\n uint[] amountsToForward;\\r\\n }\\r\\n\\r\\n /// @notice Input params for _recycle\\r\\n struct RecycleParams {\\r\\n ITetuConverter converter;\\r\\n ITetuLiquidator liquidator;\\r\\n address insurance;\\r\\n /// @notice Underlying asset\\r\\n address asset;\\r\\n /// @notice tokens received from {_depositorPoolAssets}\\r\\n address[] tokens;\\r\\n /// @notice Full list of reward tokens received from tetuConverter and depositor\\r\\n address[] rewardTokens;\\r\\n /// @notice Liquidation thresholds for rewards tokens\\r\\n uint[] thresholds;\\r\\n /// @notice Compound ration in the range [0...COMPOUND_DENOMINATOR]\\r\\n uint compoundRatio;\\r\\n /// @notice Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n uint[] rewardAmounts;\\r\\n /// @notice Performance fee in the range [0...FEE_DENOMINATOR]\\r\\n uint performanceFee;\\r\\n /// @notice Current debt to the insurance [in underlying]\\r\\n int debtToInsurance;\\r\\n /// @notice Liquidation threshold for the {asset}\\r\\n uint assetThreshold;\\r\\n }\\r\\n//endregion--------------------------------------------------- Data types\\r\\n\\r\\n//region--------------------------------------------------- Constants\\r\\n\\r\\n /// @notice approx one month for average block time 2 sec\\r\\n uint internal constant _LOAN_PERIOD_IN_BLOCKS = 30 days / 2;\\r\\n uint internal constant _REWARD_LIQUIDATION_SLIPPAGE = 5_000; // 5%\\r\\n uint internal constant COMPOUND_DENOMINATOR = 100_000;\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n uint internal constant PRICE_IMPACT_TOLERANCE = 300;\\r\\n /// @notice borrow/collateral amount cannot be less than given number of tokens\\r\\n uint internal constant DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD = 10;\\r\\n /// @notice Allow to swap more then required (i.e. 1_000 => +1%) inside {swapToGivenAmount}\\r\\n /// to avoid additional swap if the swap will return amount a bit less than we expected\\r\\n uint internal constant OVERSWAP = PRICE_IMPACT_TOLERANCE + _ASSET_LIQUIDATION_SLIPPAGE;\\r\\n /// @notice During SWAP-REPAY cycle we can receive requested amount after SWAP, so, following REPAY will be skipped.\\r\\n /// But we should prevent situation \\\"zero balance, not zero debts\\\".\\r\\n /// So, it worth to request amount higher (on the given gap) than it's really requested.\\r\\n uint internal constant REQUESTED_BALANCE_GAP = 5_000; // 5%\\r\\n\\r\\n /// @notice Normally insurance should be equal to 3% of TVL (AppLib.DENOMINATOR is used)\\r\\n uint internal constant TARGET_INSURANCE_TVL_RATIO = 3_000;\\r\\n//endregion--------------------------------------------------- Constants\\r\\n\\r\\n//region--------------------------------------------------- Events\\r\\n /// @notice A borrow was made\\r\\n event OpenPosition(\\r\\n address converter,\\r\\n address collateralAsset,\\r\\n uint collateralAmount,\\r\\n address borrowAsset,\\r\\n uint borrowedAmount,\\r\\n address recepient\\r\\n );\\r\\n\\r\\n /// @notice Some borrow(s) was/were repaid\\r\\n event ClosePosition(\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n address recepient,\\r\\n uint returnedAssetAmountOut,\\r\\n uint returnedBorrowAmountOut\\r\\n );\\r\\n\\r\\n /// @notice A liquidation was made\\r\\n event Liquidation(\\r\\n address tokenIn,\\r\\n address tokenOut,\\r\\n uint amountIn,\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n );\\r\\n\\r\\n event ReturnAssetToConverter(address asset, uint amount);\\r\\n\\r\\n /// @notice Recycle was made\\r\\n /// @param rewardTokens Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param amountsToForward Amounts to be sent to forwarder\\r\\n event Recycle(\\r\\n address[] rewardTokens,\\r\\n uint[] amountsToForward,\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by rewards\\r\\n /// @param debtToInsuranceBefore Initial amount of debts to the insurance, in underlying\\r\\n /// @param debtToInsuranceBefore Final amount of debts to the insurance, in underlying\\r\\n event OnPayDebtToInsurance(\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuraneAfter\\r\\n );\\r\\n\\r\\n /// @notice Debt to insurance was paid by a reward token\\r\\n /// @param debtToCover Initial amount of debt that should be covered, in underlying\\r\\n /// @param debtLeftovers Final amount of debt that should be covered, in underlying\\r\\n /// It can be negative if we paid more than required\\r\\n event OnCoverDebtToInsurance(\\r\\n address rewardToken,\\r\\n uint rewardAmount,\\r\\n uint debtToCover,\\r\\n int debtLeftovers\\r\\n );\\r\\n//endregion--------------------------------------------------- Events\\r\\n\\r\\n//region--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n function openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) external returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n return _openPosition(tetuConverter_, entryData_, collateralAsset_, borrowAsset_, amountIn_, thresholdAmountIn_);\\r\\n }\\r\\n\\r\\n /// @notice Make one or several borrow necessary to supply/borrow required {amountIn_} according to {entryData_}\\r\\n /// Max possible collateral should be approved before calling of this function.\\r\\n /// @param entryData_ Encoded entry kind and additional params if necessary (set of params depends on the kind)\\r\\n /// See TetuConverter\\\\EntryKinds.sol\\\\ENTRY_KIND_XXX constants for possible entry kinds\\r\\n /// 0 or empty: Amount of collateral {amountIn_} is fixed, amount of borrow should be max possible.\\r\\n /// @param amountIn_ Meaning depends on {entryData_}.\\r\\n /// @param thresholdAmountIn_ Min value of amountIn allowed for the second and subsequent conversions.\\r\\n /// 0 - use default min value\\r\\n /// If amountIn becomes too low, no additional borrows are possible, so\\r\\n /// the rest amountIn is just added to collateral/borrow amount of previous conversion.\\r\\n function _openPosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint thresholdAmountIn_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n if (thresholdAmountIn_ == 0) {\\r\\n // zero threshold is not allowed because round-issues are possible, see openPosition.dust test\\r\\n // we assume here, that it's useless to borrow amount using collateral/borrow amount\\r\\n // less than given number of tokens (event for BTC)\\r\\n thresholdAmountIn_ = DEFAULT_OPEN_POSITION_AMOUNT_IN_THRESHOLD;\\r\\n }\\r\\n if (amountIn_ <= thresholdAmountIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n OpenPositionLocal memory vars;\\r\\n // we assume here, that max possible collateral amount is already approved (as it's required by TetuConverter)\\r\\n vars.entryKind = ConverterEntryKinds.getEntryKind(entryData_);\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_PROPORTION_1) {\\r\\n return openPositionEntryKind1(\\r\\n tetuConverter_,\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n borrowAsset_,\\r\\n amountIn_,\\r\\n thresholdAmountIn_\\r\\n );\\r\\n } else {\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // we need to approve collateralAmount before the borrow-call but it's already approved, see above comments\\r\\n vars.collateral;\\r\\n vars.amountToBorrow;\\r\\n if (vars.entryKind == ConverterEntryKinds.ENTRY_KIND_EXACT_COLLATERAL_IN_FOR_MAX_BORROW_OUT_0) {\\r\\n // we have exact amount of total collateral amount\\r\\n // Case ENTRY_KIND_EXACT_PROPORTION_1 is here too because we consider first platform only\\r\\n vars.collateral = amountIn_ < vars.collateralsRequired[i]\\r\\n ? amountIn_\\r\\n : vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = amountIn_ < vars.collateralsRequired[i]\\r\\n ? vars.amountsToBorrow[i] * amountIn_ / vars.collateralsRequired[i]\\r\\n : vars.amountsToBorrow[i];\\r\\n amountIn_ -= vars.collateral;\\r\\n } else {\\r\\n // assume here that entryKind == EntryKinds.ENTRY_KIND_EXACT_BORROW_OUT_FOR_MIN_COLLATERAL_IN_2\\r\\n // we have exact amount of total amount-to-borrow\\r\\n vars.amountToBorrow = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? amountIn_\\r\\n : vars.amountsToBorrow[i];\\r\\n vars.collateral = amountIn_ < vars.amountsToBorrow[i]\\r\\n ? vars.collateralsRequired[i] * amountIn_ / vars.amountsToBorrow[i]\\r\\n : vars.collateralsRequired[i];\\r\\n amountIn_ -= vars.amountToBorrow;\\r\\n }\\r\\n\\r\\n if (amountIn_ < thresholdAmountIn_ && amountIn_ != 0) {\\r\\n // dust amount is left, just leave it unused\\r\\n // we cannot add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n amountIn_ = 0;\\r\\n }\\r\\n\\r\\n if (vars.amountToBorrow != 0) {\\r\\n borrowedAmountOut += tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n collateralAmountOut += vars.collateral;\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n }\\r\\n\\r\\n if (amountIn_ == 0) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Open position using entry kind 1 - split provided amount on two parts according provided proportions\\r\\n /// @param amountIn_ Amount of collateral to be divided on parts. We assume {amountIn_} > 0\\r\\n /// @param collateralThreshold_ Min allowed collateral amount to be used for new borrow, > 0\\r\\n /// @return collateralAmountOut Total collateral used to borrow {borrowedAmountOut}\\r\\n /// @return borrowedAmountOut Total borrowed amount\\r\\n function openPositionEntryKind1(\\r\\n ITetuConverter tetuConverter_,\\r\\n bytes memory entryData_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_,\\r\\n uint amountIn_,\\r\\n uint collateralThreshold_\\r\\n ) internal returns (\\r\\n uint collateralAmountOut,\\r\\n uint borrowedAmountOut\\r\\n ) {\\r\\n OpenPositionEntryKind1Local memory vars;\\r\\n (vars.converters, vars.collateralsRequired, vars.amountsToBorrow,) = tetuConverter_.findBorrowStrategies(\\r\\n entryData_,\\r\\n collateralAsset_,\\r\\n amountIn_,\\r\\n borrowAsset_,\\r\\n _LOAN_PERIOD_IN_BLOCKS\\r\\n );\\r\\n\\r\\n uint len = vars.converters.length;\\r\\n if (len > 0) {\\r\\n // we should split amountIn on two amounts with proportions x:y\\r\\n (, uint x, uint y) = abi.decode(entryData_, (uint, uint, uint));\\r\\n // calculate prices conversion ratio using price oracle, decimals 18\\r\\n // i.e. alpha = 1e18 * 75e6 usdc / 25e18 matic = 3e6 usdc/matic\\r\\n vars.alpha = _getCollateralToBorrowRatio(tetuConverter_, collateralAsset_, borrowAsset_);\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // the lending platform allows to convert {collateralsRequired[i]} to {amountsToBorrow[i]}\\r\\n // and give us required proportions in result\\r\\n // C = C1 + C2, C2 => B2, B2 * alpha = C3, C1/C3 must be equal to x/y\\r\\n // C1 is collateral amount left untouched (x)\\r\\n // C2 is collateral amount converted to B2 (y)\\r\\n // but if lending platform doesn't have enough liquidity\\r\\n // it reduces {collateralsRequired[i]} and {amountsToBorrow[i]} proportionally to fit the limits\\r\\n // as result, remaining C1 will be too big after conversion and we need to make another borrow\\r\\n vars.c3 = vars.alpha * vars.amountsToBorrow[i] / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n\\r\\n // we doesn't calculate an intermediate ratio cR/(cR+c1) to avoid lost of precision\\r\\n if ((vars.collateralsRequired[i] + vars.c1) > amountIn_) {\\r\\n vars.collateral = vars.collateralsRequired[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i] * amountIn_ / (vars.collateralsRequired[i] + vars.c1);\\r\\n } else {\\r\\n vars.collateral = vars.collateralsRequired[i];\\r\\n vars.amountToBorrow = vars.amountsToBorrow[i];\\r\\n }\\r\\n\\r\\n // skip any attempts to borrow zero amount or use too little collateral\\r\\n if (vars.collateral < collateralThreshold_ || vars.amountToBorrow == 0) {\\r\\n if (vars.collateralsRequired[i] + vars.c1 + collateralThreshold_ > amountIn_) {\\r\\n // The lending platform has enough resources to make the borrow but amount of the borrow is too low\\r\\n // Skip the borrow, leave leftover of collateral untouched\\r\\n break;\\r\\n } else {\\r\\n // The lending platform doesn't have enough resources to make the borrow.\\r\\n // We should try to make borrow on the next platform (if any)\\r\\n continue;\\r\\n }\\r\\n }\\r\\n\\r\\n require(\\r\\n tetuConverter_.borrow(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n ) == vars.amountToBorrow,\\r\\n StrategyLib2.WRONG_VALUE\\r\\n );\\r\\n emit OpenPosition(\\r\\n vars.converters[i],\\r\\n collateralAsset_,\\r\\n vars.collateral,\\r\\n borrowAsset_,\\r\\n vars.amountToBorrow,\\r\\n address(this)\\r\\n );\\r\\n\\r\\n borrowedAmountOut += vars.amountToBorrow;\\r\\n collateralAmountOut += vars.collateral;\\r\\n\\r\\n // calculate amount to be borrowed in the next converter\\r\\n vars.c3 = vars.alpha * vars.amountToBorrow / 1e18;\\r\\n vars.c1 = x * vars.c3 / y;\\r\\n amountIn_ = (amountIn_ > vars.c1 + vars.collateral)\\r\\n ? amountIn_ - (vars.c1 + vars.collateral)\\r\\n : 0;\\r\\n\\r\\n // protection against dust amounts, see \\\"openPosition.dust\\\", just leave dust amount unused\\r\\n // we CAN NOT add it to collateral/borrow amounts - there is a risk to exceed max allowed amounts\\r\\n // we assume here, that collateralThreshold_ != 0, so check amountIn_ != 0 is not required\\r\\n if (amountIn_ < collateralThreshold_) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return (collateralAmountOut, borrowedAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Get ratio18 = collateral / borrow\\r\\n function _getCollateralToBorrowRatio(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset_,\\r\\n address borrowAsset_\\r\\n ) internal view returns (uint){\\r\\n IPriceOracle priceOracle = AppLib._getPriceOracle(converter_);\\r\\n uint priceCollateral = priceOracle.getAssetPrice(collateralAsset_);\\r\\n uint priceBorrow = priceOracle.getAssetPrice(borrowAsset_);\\r\\n return 1e18 * priceBorrow * 10 ** IERC20Metadata(collateralAsset_).decimals()\\r\\n / priceCollateral / 10 ** IERC20Metadata(borrowAsset_).decimals();\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// It doesn't repay more than the actual amount of the debt, so it can use less amount than {amountToRepay}\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePosition(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // We shouldn't try to pay more than we actually need to repay\\r\\n // The leftover will be swapped inside TetuConverter, it's inefficient.\\r\\n // Let's limit amountToRepay by needToRepay-amount\\r\\n (uint needToRepay,) = converter_.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n uint amountRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n return _closePositionExact(converter_, collateralAsset, borrowAsset, amountRepay, balanceBefore);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountRepay} exactly and ensure that all amount was accepted,\\r\\n /// @param amountRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @param balanceBorrowAsset Current balance of the borrow asset\\r\\n /// @return collateralOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function _closePositionExact(\\r\\n ITetuConverter converter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountRepay,\\r\\n uint balanceBorrowAsset\\r\\n ) internal returns (\\r\\n uint collateralOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n if (amountRepay >= AppLib.DUST_AMOUNT_TOKENS) {\\r\\n // Make full/partial repayment\\r\\n IERC20(borrowAsset).safeTransfer(address(converter_), amountRepay);\\r\\n\\r\\n uint notUsedAmount;\\r\\n (collateralOut, notUsedAmount,,) = converter_.repay(collateralAsset, borrowAsset, amountRepay, address(this));\\r\\n\\r\\n emit ClosePosition(collateralAsset, borrowAsset, amountRepay, address(this), collateralOut, notUsedAmount);\\r\\n uint balanceAfter = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // we cannot use amountRepay here because AAVE pool adapter is able to send tiny amount back (debt-gap)\\r\\n repaidAmountOut = balanceBorrowAsset > balanceAfter\\r\\n ? balanceBorrowAsset - balanceAfter\\r\\n : 0;\\r\\n require(notUsedAmount == 0, StrategyLib2.WRONG_VALUE);\\r\\n }\\r\\n\\r\\n return (collateralOut, repaidAmountOut);\\r\\n }\\r\\n\\r\\n /// @notice Close the given position, pay {amountToRepay}, return collateral amount in result\\r\\n /// @param amountToRepay Amount to repay in terms of {borrowAsset}\\r\\n /// @return returnedAssetAmountOut Amount of collateral received back after repaying\\r\\n /// @return repaidAmountOut Amount that was actually repaid\\r\\n function closePosition(\\r\\n ITetuConverter tetuConverter_,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) external returns (\\r\\n uint returnedAssetAmountOut,\\r\\n uint repaidAmountOut\\r\\n ) {\\r\\n return _closePosition(tetuConverter_, collateralAsset, borrowAsset, amountToRepay);\\r\\n }\\r\\n//endregion--------------------------------------------------- Borrow and close positions\\r\\n\\r\\n//region--------------------------------------------------- Liquidation\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function liquidate(\\r\\n ITetuConverter converter,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) external returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n return _liquidate(converter, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, liquidationThresholdForTokenIn_, skipValidation);\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation if estimated amountOut exceeds the given threshold\\r\\n /// @param liquidationThresholdForTokenIn_ Liquidation threshold for {amountIn_}\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n /// @return spentAmountIn Amount of {tokenIn} has been consumed by the liquidator (== 0 | amountIn_)\\r\\n /// @return receivedAmountOut Amount of {tokenOut_} has been returned by the liquidator\\r\\n function _liquidate(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n uint liquidationThresholdForTokenIn_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we check amountIn by threshold, not amountOut\\r\\n // because {_closePositionsToGetAmount} is implemented in {get plan, make action}-way\\r\\n // {_closePositionsToGetAmount} can be used with swap by aggregators, where amountOut cannot be calculate\\r\\n // at the moment of plan building. So, for uniformity, only amountIn is checked everywhere\\r\\n\\r\\n if (amountIn_ <= liquidationThresholdForTokenIn_) {\\r\\n return (0, 0);\\r\\n }\\r\\n\\r\\n (ITetuLiquidator.PoolData[] memory route,) = liquidator_.buildRoute(tokenIn_, tokenOut_);\\r\\n\\r\\n require(route.length != 0, AppErrors.NO_LIQUIDATION_ROUTE);\\r\\n\\r\\n // if the expected value is higher than threshold distribute to destinations\\r\\n return (amountIn_, _liquidateWithRoute(converter_, route, liquidator_, tokenIn_, tokenOut_, amountIn_, slippage_, skipValidation));\\r\\n }\\r\\n\\r\\n /// @notice Make liquidation using given route and check correctness using TetuConverter's price oracle\\r\\n /// @param skipValidation Don't check correctness of conversion using TetuConverter's oracle (i.e. for reward tokens)\\r\\n function _liquidateWithRoute(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator.PoolData[] memory route,\\r\\n ITetuLiquidator liquidator_,\\r\\n address tokenIn_,\\r\\n address tokenOut_,\\r\\n uint amountIn_,\\r\\n uint slippage_,\\r\\n bool skipValidation\\r\\n ) internal returns (\\r\\n uint receivedAmountOut\\r\\n ) {\\r\\n // we need to approve each time, liquidator address can be changed in controller\\r\\n AppLib.approveIfNeeded(tokenIn_, amountIn_, address(liquidator_));\\r\\n\\r\\n uint balanceBefore = IERC20(tokenOut_).balanceOf(address(this));\\r\\n liquidator_.liquidateWithRoute(route, amountIn_, slippage_);\\r\\n uint balanceAfter = IERC20(tokenOut_).balanceOf(address(this));\\r\\n\\r\\n require(balanceAfter > balanceBefore, AppErrors.BALANCE_DECREASE);\\r\\n receivedAmountOut = balanceAfter - balanceBefore;\\r\\n\\r\\n // Oracle in TetuConverter \\\"knows\\\" only limited number of the assets\\r\\n // It may not know prices for reward assets, so for rewards this validation should be skipped to avoid TC-4 error\\r\\n require(skipValidation || converter_.isConversionValid(tokenIn_, amountIn_, tokenOut_, receivedAmountOut, slippage_), AppErrors.PRICE_IMPACT);\\r\\n emit Liquidation(tokenIn_, tokenOut_, amountIn_, amountIn_, receivedAmountOut);\\r\\n }\\r\\n//endregion--------------------------------------------------- Liquidation\\r\\n\\r\\n//region--------------------------------------------------- Recycle rewards\\r\\n\\r\\n /// @notice Calculate effective values of performance fee and performance fee ratio depending on TVK and insurance balance.\\r\\n /// Terms:\\r\\n /// P1 - percent of rewards that should be sent to performance receiver\\r\\n /// P2 - max percent of rewards that can be sent to the insurance.\\r\\n /// P2' - effective value of P2 = percent of rewards that should be sent to the insurance.\\r\\n /// @param performanceFee Performance fee from configuration, decimals = AppLib.DENOMINATOR\\r\\n /// Performance fee = P1 + P2\\r\\n /// Actual (effective) value of P2 depends on current TVL and insurance balance.\\r\\n /// Insurance balance should be equal 3% of TVL. If required balance is reached, P2' = 0.\\r\\n /// In other case P2' ~ difference of (3% of TVL - insurance balance).\\r\\n /// @param performanceFeeRatio Ratio between P1 and P2. 100_000 means P2 = 0, 0 means P1 = 0\\r\\n /// @param tvl Current TVL of the vault\\r\\n /// @param insurance Address of the insurance contract\\r\\n /// @return effectivePerformanceFee Effective percent of performance fee = P1 + P2', where P2' is actual percent\\r\\n /// of rewards that should be sent to the insurance.\\r\\n /// @return effectivePerformanceFeeRatio Ratio between P1 and P2'.\\r\\n function _getEffectivePerformanceFee(\\r\\n uint performanceFee,\\r\\n uint performanceFeeRatio,\\r\\n uint tvl,\\r\\n address asset,\\r\\n address insurance\\r\\n ) internal view returns (\\r\\n uint effectivePerformanceFee,\\r\\n uint effectivePerformanceFeeRatio\\r\\n ) {\\r\\n uint targetBalance = tvl * TARGET_INSURANCE_TVL_RATIO / AppLib.DENOMINATOR;\\r\\n uint insuranceBalance = IERC20(asset).balanceOf(insurance);\\r\\n uint toPerf = performanceFee * performanceFeeRatio / AppLib.DENOMINATOR;\\r\\n uint toInsurance = insuranceBalance >= targetBalance || targetBalance == 0\\r\\n ? 0\\r\\n : (targetBalance - insuranceBalance) * performanceFee * (AppLib.DENOMINATOR - performanceFeeRatio) / targetBalance / AppLib.DENOMINATOR;\\r\\n return (\\r\\n toPerf + toInsurance,\\r\\n toInsurance == 0 ? AppLib.DENOMINATOR : AppLib.DENOMINATOR * toPerf / (toPerf + toInsurance)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: liquidate a part of each amount, send the other part to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// Performance amounts should be liquidate, result underlying should be sent to performance receiver and insurance.\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// @dev {_recycle} is implemented as separate (inline) function to simplify unit testing\\r\\n /// @param rewardTokens_ Full list of reward tokens received from tetuConverter and depositor\\r\\n /// @param rewardAmounts_ Amounts of {rewardTokens_}; we assume, there are no zero amounts here\\r\\n /// @return paidDebtToInsurance Earned amount spent on debt-to-insurance payment\\r\\n /// @return amountPerf Performance fee in terms of underlying\\r\\n function recycle(\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address[] memory tokens,\\r\\n address controller,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_\\r\\n ) external returns (uint paidDebtToInsurance, uint amountPerf) {\\r\\n RecycleLocal memory v;\\r\\n v.asset = baseState.asset;\\r\\n v.splitter = baseState.splitter;\\r\\n v.vault = ISplitter(v.splitter).vault();\\r\\n v.insurance = address(ITetuVaultV2(v.vault).insurance());\\r\\n v.debtToInsuranceCurrent = csbs.debtToInsurance;\\r\\n\\r\\n // calculate effective performance fee in the range [0...baseState.performanceFee] depending on the insurance balance\\r\\n (v.performanceFeeEffective, v.effectivePerformanceFeeRatio) = _getEffectivePerformanceFee(\\r\\n baseState.performanceFee,\\r\\n baseState.performanceFeeRatio,\\r\\n ISplitter(v.splitter).totalAssets(),\\r\\n v.asset,\\r\\n v.insurance\\r\\n );\\r\\n\\r\\n RecycleParams memory rp = RecycleParams({\\r\\n converter: csbs.converter,\\r\\n liquidator: AppLib._getLiquidator(controller),\\r\\n asset: v.asset,\\r\\n compoundRatio: baseState.compoundRatio,\\r\\n tokens: tokens,\\r\\n thresholds: _getLiquidationThresholds(liquidationThresholds, rewardTokens_, rewardTokens_.length),\\r\\n rewardTokens: rewardTokens_,\\r\\n rewardAmounts: rewardAmounts_,\\r\\n performanceFee: v.performanceFeeEffective,\\r\\n debtToInsurance: v.debtToInsuranceCurrent,\\r\\n insurance: address(v.insurance),\\r\\n assetThreshold: AppLib._getLiquidationThreshold(liquidationThresholds[v.asset])\\r\\n });\\r\\n (v.amountsToForward, amountPerf, v.debtToInsuranceUpdated) = _recycle(rp);\\r\\n\\r\\n if (v.debtToInsuranceCurrent != v.debtToInsuranceUpdated) {\\r\\n csbs.debtToInsurance = v.debtToInsuranceUpdated;\\r\\n emit OnPayDebtToInsurance(v.debtToInsuranceCurrent, v.debtToInsuranceUpdated);\\r\\n paidDebtToInsurance = v.debtToInsuranceCurrent - v.debtToInsuranceUpdated > 0\\r\\n ? uint(v.debtToInsuranceCurrent - v.debtToInsuranceUpdated)\\r\\n : 0;\\r\\n }\\r\\n\\r\\n // send performance-part of the underlying to the performance receiver and insurance\\r\\n (v.toPerf, v.toInsurance) = _sendPerformanceFee(\\r\\n v.asset,\\r\\n amountPerf,\\r\\n v.insurance,\\r\\n baseState.performanceReceiver,\\r\\n v.effectivePerformanceFeeRatio,\\r\\n rp.assetThreshold\\r\\n );\\r\\n\\r\\n // overwrite rewardTokens_, v.amountsToForward by the values actually sent to the forwarder\\r\\n (rewardTokens_, v.amountsToForward) = _sendTokensToForwarder(controller, v.vault, rewardTokens_, v.amountsToForward, rp.thresholds);\\r\\n\\r\\n emit Recycle(rewardTokens_, v.amountsToForward, v.toPerf, v.toInsurance);\\r\\n return (paidDebtToInsurance, amountPerf);\\r\\n }\\r\\n\\r\\n /// @notice Send {amount_} of {asset_} to {receiver_} and insurance\\r\\n /// @param asset Underlying asset\\r\\n /// @param amount Amount of underlying asset to be sent to performance+insurance\\r\\n /// @param receiver Performance receiver\\r\\n /// @param ratio [0..100_000], 100_000 - send full amount to perf, 0 - send full amount to the insurance.\\r\\n /// @return toPerf Amount sent to the {receiver}\\r\\n /// @return toInsurance Amount sent to the {insurance}\\r\\n function _sendPerformanceFee(address asset, uint amount, address insurance, address receiver, uint ratio, uint threshold)\\r\\n internal returns (\\r\\n uint toPerf,\\r\\n uint toInsurance\\r\\n ) {\\r\\n toPerf = amount * ratio / AppLib.DENOMINATOR;\\r\\n toInsurance = amount - toPerf;\\r\\n\\r\\n if (toPerf != 0) {\\r\\n if (toPerf < threshold) {\\r\\n toPerf = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(receiver, toPerf);\\r\\n }\\r\\n }\\r\\n\\r\\n if (toInsurance != 0) {\\r\\n if (toInsurance < threshold) {\\r\\n toInsurance = 0;\\r\\n } else {\\r\\n IERC20(asset).safeTransfer(insurance, toInsurance);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Send {amounts_} to forwarder, skip amounts < thresholds (see SCB-812)\\r\\n /// @return tokensOut Tokens sent to the forwarder\\r\\n /// @return amountsOut Amounts sent to the forwarder\\r\\n function _sendTokensToForwarder(\\r\\n address controller_,\\r\\n address vault_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory amounts_,\\r\\n uint[] memory thresholds_\\r\\n ) internal returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n IForwarder forwarder = IForwarder(IController(controller_).forwarder());\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (thresholds_[i] > amounts_[i]) {\\r\\n amounts_[i] = 0; // it will be excluded in filterZeroAmounts() below\\r\\n } else {\\r\\n AppLib.approveIfNeeded(tokens_[i], amounts_[i], address(forwarder));\\r\\n }\\r\\n }\\r\\n\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokens_, amounts_);\\r\\n if (tokensOut.length != 0) {\\r\\n forwarder.registerIncome(tokensOut, amountsOut, vault_, true);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Recycle the amounts: split each amount on tree parts: performance+insurance (P), forwarder (F), compound (C)\\r\\n /// Liquidate P+C, send F to the forwarder.\\r\\n /// We have two kinds of rewards:\\r\\n /// 1) rewards in depositor's assets (the assets returned by _depositorPoolAssets)\\r\\n /// 2) any other rewards\\r\\n /// All received rewards divided on three parts: to performance receiver+insurance, to forwarder, to compound\\r\\n /// Compound-part of Rewards-2 can be liquidated\\r\\n /// Compound part of Rewards-1 should be just left on the balance\\r\\n /// All forwarder-parts are returned in amountsToForward and should be transferred to the forwarder outside.\\r\\n /// Performance amounts are liquidated, result amount of underlying is returned in {amountToPerformanceAndInsurance}\\r\\n /// @return amountsToForward Amounts of {rewardTokens} to be sent to forwarder, zero amounts are allowed here\\r\\n /// @return amountToPerformanceAndInsurance Amount of underlying to be sent to performance receiver and insurance\\r\\n /// @return debtToInsuranceOut Remain debt to the insurance [in underlying]\\r\\n function _recycle(RecycleParams memory p) internal returns (\\r\\n uint[] memory amountsToForward,\\r\\n uint amountToPerformanceAndInsurance,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n RecycleLocalParams memory v;\\r\\n\\r\\n v.len = p.rewardTokens.length;\\r\\n require(v.len == p.rewardAmounts.length, AppErrors.WRONG_LENGTHS);\\r\\n\\r\\n amountsToForward = new uint[](v.len);\\r\\n\\r\\n // rewardAmounts => P + F + C, where P - performance + insurance, F - forwarder, C - compound\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n // if we have a debt-to-insurance we should firstly cover the debt using all available rewards\\r\\n // and only then we can use leftovers of the rewards for other needs\\r\\n if (p.debtToInsurance > int(p.assetThreshold)) {\\r\\n (p.rewardAmounts[i], p.debtToInsurance) = _coverDebtToInsuranceFromRewards(p, i, uint(p.debtToInsurance));\\r\\n if (p.rewardAmounts[i] < p.thresholds[i]) continue;\\r\\n }\\r\\n\\r\\n v.amountFC = p.rewardAmounts[i] * (COMPOUND_DENOMINATOR - p.performanceFee) / COMPOUND_DENOMINATOR;\\r\\n v.amountC = v.amountFC * p.compoundRatio / COMPOUND_DENOMINATOR;\\r\\n v.amountP = p.rewardAmounts[i] - v.amountFC;\\r\\n v.rewardToken = p.rewardTokens[i];\\r\\n v.amountCP = v.amountC + v.amountP;\\r\\n\\r\\n if (v.amountCP > 0) {\\r\\n if (AppLib.getAssetIndex(p.tokens, v.rewardToken) != type(uint).max) {\\r\\n if (v.rewardToken == p.asset) {\\r\\n // This is underlying, liquidation of compound part is not allowed; just keep on the balance, should be handled later\\r\\n amountToPerformanceAndInsurance += v.amountP;\\r\\n } else {\\r\\n // This is secondary asset, Liquidation of compound part is not allowed, we should liquidate performance part only\\r\\n // If the performance amount is too small, liquidation will not happen and we will just keep that dust tokens on balance forever\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n false // use conversion validation for these rewards\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut;\\r\\n }\\r\\n } else {\\r\\n // If amount is too small, the liquidation won't be allowed and we will just keep that dust tokens on balance forever\\r\\n // The asset is not in the list of depositor's assets, its amount is big enough and should be liquidated\\r\\n // We assume here, that {token} cannot be equal to {_asset}\\r\\n // because the {_asset} is always included to the list of depositor's assets\\r\\n (, v.receivedAmountOut) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n v.rewardToken,\\r\\n p.asset,\\r\\n v.amountCP,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[i],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n amountToPerformanceAndInsurance += v.receivedAmountOut * (p.rewardAmounts[i] - v.amountFC) / v.amountCP;\\r\\n }\\r\\n }\\r\\n amountsToForward[i] = v.amountFC - v.amountC;\\r\\n }\\r\\n\\r\\n return (amountsToForward, amountToPerformanceAndInsurance, p.debtToInsurance);\\r\\n }\\r\\n\\r\\n /// @notice Try to cover {p.debtToInsurance} using available rewards of {p.rewardTokens[index]}\\r\\n /// @param index Index of the reward token in {p.rewardTokens}\\r\\n /// @param debtAmount Debt to insurance that should be covered by the reward tokens\\r\\n /// @return rewardsLeftovers Amount of unused reward tokens (it can be used for other needs)\\r\\n /// @return debtToInsuranceOut New value of the debt to the insurance\\r\\n function _coverDebtToInsuranceFromRewards(RecycleParams memory p, uint index, uint debtAmount) internal returns (\\r\\n uint rewardsLeftovers,\\r\\n int debtToInsuranceOut\\r\\n ) {\\r\\n uint spentAmount;\\r\\n uint amountToSend;\\r\\n\\r\\n if (p.asset == p.rewardTokens[index]) {\\r\\n // assume p.debtToInsurance > 0 here\\r\\n spentAmount = Math.min(debtAmount, p.rewardAmounts[index]);\\r\\n amountToSend = spentAmount;\\r\\n } else {\\r\\n // estimate amount of underlying that we can receive for the available amount of the reward tokens\\r\\n uint amountAsset = p.rewardAmounts[index] > p.assetThreshold\\r\\n ? p.liquidator.getPrice(p.rewardTokens[index], p.asset, p.rewardAmounts[index])\\r\\n : 0;\\r\\n uint amountIn = amountAsset > debtAmount + p.assetThreshold\\r\\n // pay a part of the rewards to cover the debt completely\\r\\n ? p.rewardAmounts[index] * debtAmount / amountAsset\\r\\n // pay all available rewards to cover a part of the debt\\r\\n : p.rewardAmounts[index];\\r\\n\\r\\n (spentAmount, amountToSend) = _liquidate(\\r\\n p.converter,\\r\\n p.liquidator,\\r\\n p.rewardTokens[index],\\r\\n p.asset,\\r\\n amountIn,\\r\\n _REWARD_LIQUIDATION_SLIPPAGE,\\r\\n p.thresholds[index],\\r\\n true // skip conversion validation for rewards because we can have arbitrary assets here\\r\\n );\\r\\n }\\r\\n\\r\\n IERC20(p.asset).safeTransfer(p.insurance, amountToSend);\\r\\n\\r\\n rewardsLeftovers = AppLib.sub0(p.rewardAmounts[index], spentAmount);\\r\\n debtToInsuranceOut = int(debtAmount) - int(amountToSend);\\r\\n\\r\\n emit OnCoverDebtToInsurance(p.rewardTokens[index], spentAmount, debtAmount, debtToInsuranceOut);\\r\\n }\\r\\n//endregion----------------------------------------------- Recycle rewards\\r\\n\\r\\n//region--------------------------------------------------- Before deposit\\r\\n /// @notice Default implementation of ConverterStrategyBase.beforeDeposit\\r\\n /// @param amount_ Amount of underlying to be deposited\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param weights_ Depositor pool weights\\r\\n /// @param totalWeight_ Sum of {weights_}\\r\\n function beforeDeposit(\\r\\n ITetuConverter converter_,\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n // temporary save collateral to tokensAmounts\\r\\n tokenAmounts = _getCollaterals(amount_, tokens_, weights_, totalWeight_, indexAsset_, AppLib._getPriceOracle(converter_));\\r\\n\\r\\n // make borrow and save amounts of tokens available for deposit to tokenAmounts, zero result amounts are possible\\r\\n tokenAmounts = _getTokenAmounts(\\r\\n converter_,\\r\\n tokens_,\\r\\n indexAsset_,\\r\\n tokenAmounts,\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[indexAsset_]])\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice For each {token_} calculate a part of {amount_} to be used as collateral according to the weights.\\r\\n /// I.e. we have 300 USDC, we need to split it on 100 USDC, 100 USDT, 100 DAI\\r\\n /// USDC is main asset, USDT and DAI should be borrowed. We check amounts of USDT and DAI on the balance\\r\\n /// and return collaterals reduced on that amounts. For main asset, we return full amount always (100 USDC).\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @return tokenAmountsOut Length of the array is equal to the length of {tokens_}\\r\\n function _getCollaterals(\\r\\n uint amount_,\\r\\n address[] memory tokens_,\\r\\n uint[] memory weights_,\\r\\n uint totalWeight_,\\r\\n uint indexAsset_,\\r\\n IPriceOracle priceOracle\\r\\n ) internal view returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n\\r\\n // get token prices and decimals\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(priceOracle, tokens_, len);\\r\\n\\r\\n // split the amount on tokens proportionally to the weights\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n uint amountAssetForToken = amount_ * weights_[i] / totalWeight_;\\r\\n\\r\\n if (i == indexAsset_) {\\r\\n tokenAmountsOut[i] = amountAssetForToken;\\r\\n } else {\\r\\n // if we have some tokens on balance then we need to use only a part of the collateral\\r\\n uint tokenAmountToBeBorrowed = amountAssetForToken\\r\\n * prices[indexAsset_]\\r\\n * decs[i]\\r\\n / prices[i]\\r\\n / decs[indexAsset_];\\r\\n\\r\\n uint tokenBalance = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n if (tokenBalance < tokenAmountToBeBorrowed) {\\r\\n tokenAmountsOut[i] = amountAssetForToken * (tokenAmountToBeBorrowed - tokenBalance) / tokenAmountToBeBorrowed;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Make borrow and return amounts of {tokens} available to deposit\\r\\n /// @param tokens_ Tokens received from {_depositorPoolAssets}\\r\\n /// @param indexAsset_ Index of main {asset} in {tokens}\\r\\n /// @param collaterals_ Amounts of main asset that can be used as collateral to borrow {tokens_}\\r\\n /// @param thresholdAsset_ Value of liquidation threshold for the main (collateral) asset\\r\\n /// @return tokenAmountsOut Amounts of {tokens} available to deposit\\r\\n function _getTokenAmounts(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n uint[] memory collaterals_,\\r\\n uint thresholdAsset_\\r\\n ) internal returns (\\r\\n uint[] memory tokenAmountsOut\\r\\n ) {\\r\\n // content of tokenAmounts will be modified in place\\r\\n uint len = tokens_.length;\\r\\n tokenAmountsOut = new uint[](len);\\r\\n address asset = tokens_[indexAsset_];\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i != indexAsset_) {\\r\\n address token = tokens_[i];\\r\\n if (collaterals_[i] != 0) {\\r\\n AppLib.approveIfNeeded(asset, collaterals_[i], address(converter_));\\r\\n _openPosition(\\r\\n converter_,\\r\\n \\\"\\\", // entry kind = 0: fixed collateral amount, max possible borrow amount\\r\\n asset,\\r\\n token,\\r\\n collaterals_[i],\\r\\n thresholdAsset_\\r\\n );\\r\\n\\r\\n // zero borrowed amount is possible here (conversion is not available)\\r\\n // if it's not suitable for depositor, the depositor should check zero amount in other places\\r\\n }\\r\\n tokenAmountsOut[i] = IERC20(token).balanceOf(address(this));\\r\\n }\\r\\n }\\r\\n\\r\\n tokenAmountsOut[indexAsset_] = Math.min(\\r\\n collaterals_[indexAsset_],\\r\\n IERC20(asset).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n//endregion--------------------------------------------------- Before deposit\\r\\n\\r\\n//region--------------------------------------------------- Make requested amount\\r\\n\\r\\n /// @notice Convert {amountsToConvert_} to the given {asset}\\r\\n /// Swap leftovers (if any) to the given asset.\\r\\n /// If result amount is less than expected, try to close any other available debts (1 repay per block only)\\r\\n /// @param tokens_ Results of _depositorPoolAssets() call (list of depositor's asset in proper order)\\r\\n /// @param indexAsset_ Index of the given {asset} in {tokens}\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function makeRequestedAmount(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset_,\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator_,\\r\\n uint requestedBalance,\\r\\n mapping(address => uint) storage liquidationThresholds_\\r\\n ) external returns (uint expectedBalance) {\\r\\n DataSetLocal memory v = DataSetLocal({\\r\\n len: tokens_.length,\\r\\n converter: converter_,\\r\\n tokens: tokens_,\\r\\n indexAsset: indexAsset_,\\r\\n liquidator: liquidator_\\r\\n });\\r\\n uint[] memory _liquidationThresholds = _getLiquidationThresholds(liquidationThresholds_, v.tokens, v.len);\\r\\n expectedBalance = _closePositionsToGetAmount(v, _liquidationThresholds, requestedBalance);\\r\\n }\\r\\n //endregion-------------------------------------------- Make requested amount\\r\\n\\r\\n//region ------------------------------------------------ Close position\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev We assume here that this function is called before closing any positions in the current block\\r\\n /// @param liquidationThresholds Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function closePositionsToGetAmount(\\r\\n ITetuConverter converter_,\\r\\n ITetuLiquidator liquidator,\\r\\n uint indexAsset,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n uint requestedBalance,\\r\\n address[] memory tokens\\r\\n ) external returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n return _closePositionsToGetAmount(\\r\\n DataSetLocal({\\r\\n len: len,\\r\\n converter: converter_,\\r\\n tokens: tokens,\\r\\n indexAsset: indexAsset,\\r\\n liquidator: liquidator\\r\\n }),\\r\\n _getLiquidationThresholds(liquidationThresholds, tokens, len),\\r\\n requestedBalance\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Close debts (if it's allowed) in converter until we don't have {requestedAmount} on balance\\r\\n /// @dev Implements {IterationPlanLib.PLAN_SWAP_REPAY} only\\r\\n /// Note: AAVE3 allows to make two repays in a single block, see Aave3SingleBlockTest in TetuConverter\\r\\n /// but it doesn't allow to make borrow and repay in a single block.\\r\\n /// @param liquidationThresholds_ Min allowed amounts-out for liquidations\\r\\n /// @param requestedBalance Total amount of the given asset that we need to have on balance at the end.\\r\\n /// Max uint means attempt to withdraw all possible amount.\\r\\n /// @return expectedBalance Expected asset balance after all swaps and repays\\r\\n function _closePositionsToGetAmount(\\r\\n DataSetLocal memory d_,\\r\\n uint[] memory liquidationThresholds_,\\r\\n uint requestedBalance\\r\\n ) internal returns (\\r\\n uint expectedBalance\\r\\n ) {\\r\\n if (requestedBalance != 0) {\\r\\n //let's get a bit more amount on balance to prevent situation \\\"zero balance, not-zero debts\\\"\\r\\n requestedBalance = applyRequestedBalanceGap(requestedBalance);\\r\\n CloseDebtsForRequiredAmountLocal memory v;\\r\\n v.asset = d_.tokens[d_.indexAsset];\\r\\n\\r\\n // v.planKind = IterationPlanLib.PLAN_SWAP_REPAY; // PLAN_SWAP_REPAY == 0, so we don't need this line\\r\\n v.balanceAdditions = new uint[](d_.len);\\r\\n expectedBalance = IERC20(v.asset).balanceOf(address(this));\\r\\n\\r\\n (v.prices, v.decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(d_.converter), d_.tokens, d_.len);\\r\\n\\r\\n for (uint i; i < d_.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == d_.indexAsset) continue;\\r\\n\\r\\n v.balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.balanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n // Make one or several iterations. Do single swap and single repaying (both are optional) on each iteration.\\r\\n // Calculate expectedAmount of received underlying. Swap leftovers at the end even if requestedAmount is 0 at that moment.\\r\\n do {\\r\\n // generate iteration plan: [swap], [repay]\\r\\n (v.idxToSwap1, v.amountToSwap, v.idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(d_.converter), address(d_.liquidator)],\\r\\n d_.tokens,\\r\\n liquidationThresholds_,\\r\\n v.prices,\\r\\n v.decs,\\r\\n v.balanceAdditions,\\r\\n [0, IterationPlanLib.PLAN_SWAP_REPAY, 0, requestedBalance, d_.indexAsset, i, 0]\\r\\n );\\r\\n if (v.idxToSwap1 == 0 && v.idxToRepay1 == 0) break;\\r\\n\\r\\n // make swap if necessary\\r\\n uint spentAmountIn;\\r\\n if (v.idxToSwap1 != 0) {\\r\\n uint indexIn = v.idxToSwap1 - 1;\\r\\n uint indexOut = indexIn == d_.indexAsset ? i : d_.indexAsset;\\r\\n (spentAmountIn,) = _liquidate(\\r\\n d_.converter,\\r\\n d_.liquidator,\\r\\n d_.tokens[indexIn],\\r\\n d_.tokens[indexOut],\\r\\n v.amountToSwap,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n liquidationThresholds_[indexIn],\\r\\n false\\r\\n );\\r\\n\\r\\n if (indexIn == d_.indexAsset) {\\r\\n expectedBalance = AppLib.sub0(expectedBalance, spentAmountIn);\\r\\n } else if (indexOut == d_.indexAsset) {\\r\\n expectedBalance += spentAmountIn * v.prices[i] * v.decs[d_.indexAsset] / v.prices[d_.indexAsset] / v.decs[i];\\r\\n\\r\\n // if we already received enough amount on balance, we can avoid additional actions\\r\\n // to avoid high gas consumption in the cases like SCB-787\\r\\n uint balanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n if (balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) {\\r\\n v.balanceAsset = balanceAsset;\\r\\n break;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // repay a debt if necessary\\r\\n if (v.idxToRepay1 != 0) {\\r\\n uint indexBorrow = v.idxToRepay1 - 1;\\r\\n uint indexCollateral = indexBorrow == d_.indexAsset ? i : d_.indexAsset;\\r\\n uint amountToRepay = IERC20(d_.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n (uint expectedAmountOut, uint repaidAmountOut, uint amountSendToRepay) = _repayDebt(\\r\\n d_.converter,\\r\\n d_.tokens[indexCollateral],\\r\\n d_.tokens[indexBorrow],\\r\\n amountToRepay\\r\\n );\\r\\n\\r\\n if (indexBorrow == d_.indexAsset) {\\r\\n expectedBalance = expectedBalance > amountSendToRepay\\r\\n ? expectedBalance - amountSendToRepay\\r\\n : 0;\\r\\n } else if (indexCollateral == d_.indexAsset) {\\r\\n require(expectedAmountOut >= spentAmountIn, AppErrors.BALANCE_DECREASE);\\r\\n if (repaidAmountOut < amountSendToRepay) {\\r\\n // SCB-779: expectedAmountOut was estimated for amountToRepay, but we have paid repaidAmountOut only\\r\\n expectedBalance += expectedAmountOut * repaidAmountOut / amountSendToRepay;\\r\\n } else {\\r\\n expectedBalance += expectedAmountOut;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // update balances\\r\\n v.newBalanceAsset = IERC20(v.asset).balanceOf(address(this));\\r\\n v.newBalanceToken = IERC20(d_.tokens[i]).balanceOf(address(this));\\r\\n\\r\\n v.exitLoop = (v.balanceAsset == v.newBalanceAsset && v.balanceToken == v.newBalanceToken);\\r\\n v.balanceAsset = v.newBalanceAsset;\\r\\n v.balanceToken = v.newBalanceToken;\\r\\n } while (!v.exitLoop);\\r\\n\\r\\n if (v.balanceAsset + liquidationThresholds_[d_.indexAsset] > requestedBalance) break;\\r\\n }\\r\\n }\\r\\n\\r\\n return expectedBalance;\\r\\n }\\r\\n//endregion ------------------------------------------------ Close position\\r\\n\\r\\n//region ------------------------------------------------ Repay debts\\r\\n /// @notice Repay {amountIn} and get collateral in return, calculate expected amount\\r\\n /// Take into account possible debt-gap and the fact that the amount of debt may be less than {amountIn}\\r\\n /// @param amountToRepay Max available amount of borrow asset that we can repay\\r\\n /// @return expectedAmountOut Estimated amount of main asset that should be added to balance = collateral - {toSell}\\r\\n /// @return repaidAmountOut Actually paid amount\\r\\n /// @return amountSendToRepay Amount send to repay\\r\\n function _repayDebt(\\r\\n ITetuConverter converter,\\r\\n address collateralAsset,\\r\\n address borrowAsset,\\r\\n uint amountToRepay\\r\\n ) internal returns (\\r\\n uint expectedAmountOut,\\r\\n uint repaidAmountOut,\\r\\n uint amountSendToRepay\\r\\n ) {\\r\\n uint balanceBefore = IERC20(borrowAsset).balanceOf(address(this));\\r\\n\\r\\n // get amount of debt with debt-gap\\r\\n (uint needToRepay,) = converter.getDebtAmountCurrent(address(this), collateralAsset, borrowAsset, true);\\r\\n amountSendToRepay = Math.min(amountToRepay < needToRepay ? amountToRepay : needToRepay, balanceBefore);\\r\\n\\r\\n // get expected amount without debt-gap\\r\\n uint swappedAmountOut;\\r\\n (expectedAmountOut, swappedAmountOut) = converter.quoteRepay(address(this), collateralAsset, borrowAsset, amountSendToRepay);\\r\\n\\r\\n if (expectedAmountOut > swappedAmountOut) {\\r\\n // SCB-789 Following situation is possible\\r\\n // needToRepay = 100, needToRepayExact = 90 (debt gap is 10)\\r\\n // 1) amountRepay = 80\\r\\n // expectedAmountOut is calculated for 80, no problems\\r\\n // 2) amountRepay = 99,\\r\\n // expectedAmountOut is calculated for 90 + 9 (90 - repay, 9 - direct swap)\\r\\n // expectedAmountOut must be reduced on 9 here (!)\\r\\n expectedAmountOut -= swappedAmountOut;\\r\\n }\\r\\n\\r\\n // close the debt\\r\\n (, repaidAmountOut) = _closePositionExact(converter, collateralAsset, borrowAsset, amountSendToRepay, balanceBefore);\\r\\n\\r\\n return (expectedAmountOut, repaidAmountOut, amountSendToRepay);\\r\\n }\\r\\n //endregion ------------------------------------------------ Repay debts\\r\\n\\r\\n//region------------------------------------------------ Other helpers\\r\\n\\r\\n /// @return liquidationThresholdsOut Liquidation thresholds of the {tokens_}, result values > 0\\r\\n function _getLiquidationThresholds(\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n address[] memory tokens_,\\r\\n uint len\\r\\n ) internal view returns (\\r\\n uint[] memory liquidationThresholdsOut\\r\\n ) {\\r\\n liquidationThresholdsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n liquidationThresholdsOut[i] = AppLib._getLiquidationThreshold(liquidationThresholds[tokens_[i]]);\\r\\n }\\r\\n }\\r\\n\\r\\n function applyRequestedBalanceGap(uint amount_) internal pure returns (uint) {\\r\\n return amount_ == type(uint).max\\r\\n ? amount_\\r\\n : amount_ * (COMPOUND_DENOMINATOR + REQUESTED_BALANCE_GAP) / COMPOUND_DENOMINATOR;\\r\\n }\\r\\n//endregion--------------------------------------------- Other helpers\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0x267032ed9ee572a43825652ced9d998266f8eed6ff02b9cc9b4d11da1e052c63\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/ConverterStrategyBaseLib2.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IForwarder.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuVaultV2.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ISplitter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/strategy/StrategyLib.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IPriceOracle.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/openzeppelin/Math.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IConverterController.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IStrategyV3.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/IBookkeeper.sol\\\";\\r\\nimport \\\"../libs/AppErrors.sol\\\";\\r\\nimport \\\"../libs/AppLib.sol\\\";\\r\\nimport \\\"../libs/TokenAmountsLib.sol\\\";\\r\\nimport \\\"../libs/ConverterEntryKinds.sol\\\";\\r\\nimport \\\"../interfaces/IConverterStrategyBase.sol\\\";\\r\\n\\r\\n/// @notice Continuation of ConverterStrategyBaseLib (workaround for size limits)\\r\\nlibrary ConverterStrategyBaseLib2 {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region --------------------------------------- Data types\\r\\n struct CalcInvestedAssetsLocal {\\r\\n uint len;\\r\\n uint[] debts;\\r\\n address asset;\\r\\n address token;\\r\\n }\\r\\n//endregion --------------------------------------- Data types\\r\\n\\r\\n//region --------------------------------------- CONSTANTS\\r\\n uint internal constant DENOMINATOR = 100_000;\\r\\n\\r\\n /// @dev 0.5% of max loss for strategy TVL\\r\\n /// @notice Same value as StrategySplitterV2.HARDWORK_LOSS_TOLERANCE\\r\\n uint public constant HARDWORK_LOSS_TOLERANCE = 500;\\r\\n\\r\\n /// @dev 0.5% of max profit for strategy TVL\\r\\n /// @notice Limit max amount of profit that can be send to insurance after price changing\\r\\n uint public constant PRICE_CHANGE_PROFIT_TOLERANCE = HARDWORK_LOSS_TOLERANCE;\\r\\n\\r\\n//endregion --------------------------------------- CONSTANTS\\r\\n\\r\\n//region----------------------------------------- EVENTS\\r\\n event LiquidationThresholdChanged(address token, uint amount);\\r\\n event ReinvestThresholdPercentChanged(uint amount);\\r\\n event SendToInsurance(uint sentAmount, uint unsentAmount);\\r\\n\\r\\n /// @notice Increase to debts between new and previous checkpoints.\\r\\n /// @param tokens List of possible collateral/borrow assets. One of the is underlying.\\r\\n /// @param deltaGains Amounts by which the debt has reduced (supply profit) [sync with {tokens}]\\r\\n /// @param deltaLosses Amounts by which the debt has increased (increase of amount-to-pay) [sync with {tokens}]\\r\\n /// @param prices Prices of the {tokens}\\r\\n /// @param increaseToDebt Total amount of increasing of the debt to the insurance in underlying\\r\\n event OnIncreaseDebtToInsurance(\\r\\n address[] tokens,\\r\\n uint[] deltaGains,\\r\\n uint[] deltaLosses,\\r\\n uint[] prices,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param debtToInsuranceBefore Value of the debt to insurance before fix price change\\r\\n /// @param debtToInsuranceAfter New value of the debt to insurance\\r\\n /// @param increaseToDebt Amount on which debt to insurance was increased.\\r\\n /// Actual value {debtToInsuranceAfter}-{debtToInsuranceBefore} can be less than increaseToDebt\\r\\n /// because some amount can be left uncovered.\\r\\n event FixPriceChanges(\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsOut,\\r\\n int debtToInsuranceBefore,\\r\\n int debtToInsuranceAfter,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @param lossToCover Amount of loss that should be covered (it fits to allowed limits, no revert)\\r\\n /// @param debtToInsuranceInc The amount by which the debt to insurance increases\\r\\n /// @param amountCovered Actually covered amount of loss. If amountCovered < lossToCover => the insurance is not enough\\r\\n /// @param lossUncovered Amount of uncovered losses (not enough insurance)\\r\\n event OnCoverLoss(\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc,\\r\\n uint amountCovered,\\r\\n uint lossUncovered\\r\\n );\\r\\n\\r\\n /// @notice Value of {debtToInsurance} was increased on {increaseToDebt} inside fix-price-change\\r\\n /// in the case when invested-asset amounts were increased.\\r\\n /// @dev See comments in {_coverLossAfterPriceChanging}: actual profit-to-cover amount can be less than {increaseToDebt}\\r\\n /// @param debtToInsuranceBefore Value of debtToInsurance before fix-price-change\\r\\n /// @param increaseToDebt Value on which {debtToInsuranceBefore} was incremented\\r\\n event ChangeDebtToInsuranceOnProfit(\\r\\n int debtToInsuranceBefore,\\r\\n int increaseToDebt\\r\\n );\\r\\n\\r\\n /// @notice Amount {lossCovered}+{lossUncovered} should be covered, but it's too high and will produce revert\\r\\n /// on the splitter side. So, only {lossCovered} can be covered, {lossUncovered} are not covered\\r\\n event UncoveredLoss(uint lossCovered, uint lossUncovered, uint investedAssetsBefore, uint investedAssetsAfter);\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// @param gains Amount received by all pool adapters for the provided collateral, in underlying\\r\\n /// @param losses Amount paid by all pool adapters for the debts, in underlying\\r\\n event BorrowResults(uint gains, uint losses);\\r\\n\\r\\n /// @notice An amount (earned - earnedByPrice) is earned on withdraw and sent to the insurance\\r\\n /// @dev We assume that earned > earnedByPrice, but it's better to save raw values\\r\\n event OnEarningOnWithdraw(uint earned, uint earnedByPrice);\\r\\n\\r\\n//endregion----------------------------------------- EVENTS\\r\\n\\r\\n//region----------------------------------------- MAIN LOGIC\\r\\n /// @notice Get balances of the {tokens_} except balance of the token at {indexAsset} position\\r\\n function getAvailableBalances(\\r\\n address[] memory tokens_,\\r\\n uint indexAsset\\r\\n ) external view returns (uint[] memory) {\\r\\n uint len = tokens_.length;\\r\\n uint[] memory amountsToConvert = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) continue;\\r\\n amountsToConvert[i] = IERC20(tokens_[i]).balanceOf(address(this));\\r\\n }\\r\\n return amountsToConvert;\\r\\n }\\r\\n\\r\\n\\r\\n /// @notice Calculate amount of liquidity that should be withdrawn from the pool to get {targetAmount_}\\r\\n /// liquidityAmount = _depositorLiquidity() * {liquidityRatioOut} / 1e18\\r\\n /// User needs to withdraw {targetAmount_} in some asset.\\r\\n /// There are three kinds of available liquidity:\\r\\n /// 1) liquidity in the pool - {depositorLiquidity_}\\r\\n /// 2) Converted amounts on balance of the strategy - {baseAmounts_}\\r\\n /// 3) Liquidity locked in the debts.\\r\\n /// @param targetAmount Required amount of main asset to be withdrawn from the strategy; type(uint).max - withdraw all\\r\\n /// @param quoteAmounts Results of _depositorQuoteExit(depositorLiquidity)\\r\\n /// @return resultAmount Amount of liquidity that should be withdrawn from the pool, cannot exceed depositorLiquidity\\r\\n function getLiquidityAmount(\\r\\n uint targetAmount,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory quoteAmounts,\\r\\n uint depositorLiquidity,\\r\\n uint indexUnderlying\\r\\n ) external view returns (\\r\\n uint resultAmount\\r\\n ) {\\r\\n // total amount of assetsInPool recalculated to the underlying\\r\\n // we need to calculate this value in the case of partial withdraw only\\r\\n // so we assume below that it is equal to 0 if full withdraw is required\\r\\n uint totalUnderlying;\\r\\n\\r\\n if (targetAmount != type(uint).max) {\\r\\n // reduce targetAmount_ on the amounts of not-underlying assets available on the balance\\r\\n uint len = tokens.length;\\r\\n (uint[] memory prices, uint[] memory decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter), tokens, len);\\r\\n\\r\\n // calculate total amount of assets invested to the pool\\r\\n for (uint i; i < tokens.length; i = AppLib.uncheckedInc(i)) {\\r\\n totalUnderlying += (indexAsset == i)\\r\\n ? quoteAmounts[i]\\r\\n : quoteAmounts[i] * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n }\\r\\n\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n // assume here that the targetAmount_ is already reduced on available balance of the target asset\\r\\n if (indexAsset == i) continue;\\r\\n\\r\\n uint tokenBalance = IERC20(tokens[i]).balanceOf(address(this));\\r\\n if (tokenBalance != 0) {\\r\\n uint tokenBalanceInAsset = tokenBalance * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n\\r\\n targetAmount = targetAmount > tokenBalanceInAsset\\r\\n ? targetAmount - tokenBalanceInAsset\\r\\n : 0;\\r\\n\\r\\n uint tokenBalanceInUnderlying = indexUnderlying == indexAsset\\r\\n ? tokenBalanceInAsset\\r\\n : tokenBalance * prices[i] * decs[indexUnderlying] / prices[indexUnderlying] / decs[i];\\r\\n\\r\\n totalUnderlying = totalUnderlying > tokenBalanceInUnderlying\\r\\n ? totalUnderlying - tokenBalanceInUnderlying\\r\\n : 0;\\r\\n }\\r\\n }\\r\\n\\r\\n if (indexAsset != indexUnderlying) {\\r\\n // convert targetAmount_ to underlying\\r\\n targetAmount = targetAmount * prices[indexAsset] * decs[indexUnderlying] / prices[indexUnderlying] / decs[indexAsset];\\r\\n }\\r\\n }\\r\\n\\r\\n uint liquidityRatioOut = totalUnderlying == 0\\r\\n ? 1e18\\r\\n : ((targetAmount == 0)\\r\\n ? 0\\r\\n : 1e18 * 101 * targetAmount / totalUnderlying / 100 // a part of amount that we are going to withdraw + 1% on top\\r\\n );\\r\\n\\r\\n resultAmount = liquidityRatioOut == 0\\r\\n ? 0\\r\\n : Math.min(liquidityRatioOut * depositorLiquidity / 1e18, depositorLiquidity);\\r\\n }\\r\\n\\r\\n /// @notice Claim rewards from tetuConverter, generate result list of all available rewards and airdrops\\r\\n /// @dev The post-processing is rewards conversion to the main asset\\r\\n /// @param tokens_ tokens received from {_depositorPoolAssets}\\r\\n /// @param rewardTokens_ List of rewards claimed from the internal pool\\r\\n /// @param rewardTokens_ Amounts of rewards claimed from the internal pool\\r\\n /// @param tokensOut List of available rewards - not zero amounts, reward tokens don't repeat\\r\\n /// @param amountsOut Amounts of available rewards\\r\\n function claimConverterRewards(\\r\\n ITetuConverter converter_,\\r\\n address[] memory tokens_,\\r\\n address[] memory rewardTokens_,\\r\\n uint[] memory rewardAmounts_,\\r\\n uint[] memory balancesBefore\\r\\n ) external returns (\\r\\n address[] memory tokensOut,\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n // Rewards from TetuConverter\\r\\n (address[] memory tokensTC, uint[] memory amountsTC) = converter_.claimRewards(address(this));\\r\\n\\r\\n // Join arrays and recycle tokens\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.combineArrays(\\r\\n rewardTokens_, rewardAmounts_,\\r\\n tokensTC, amountsTC,\\r\\n // by default, depositor assets have zero amounts here\\r\\n tokens_, new uint[](tokens_.length)\\r\\n );\\r\\n\\r\\n // set fresh balances for depositor tokens\\r\\n uint len = tokensOut.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n for (uint j; j < tokens_.length; j = AppLib.uncheckedInc(j)) {\\r\\n if (tokensOut[i] == tokens_[j]) {\\r\\n amountsOut[i] = IERC20(tokens_[j]).balanceOf(address(this)) - balancesBefore[j];\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // filter zero amounts out\\r\\n (tokensOut, amountsOut) = TokenAmountsLib.filterZeroAmounts(tokensOut, amountsOut);\\r\\n }\\r\\n\\r\\n /// @notice Get price of {tokenB} in term of {tokenA} with 18 decimals\\r\\n function getOracleAssetsPrice(ITetuConverter converter, address tokenA, address tokenB) external view returns (\\r\\n uint price\\r\\n ) {\\r\\n IPriceOracle oracle = AppLib._getPriceOracle(converter);\\r\\n uint priceA = oracle.getAssetPrice(tokenA);\\r\\n uint priceB = oracle.getAssetPrice(tokenB);\\r\\n price = priceA > 0 ? 1e18 * priceB / priceA : type(uint).max;\\r\\n }\\r\\n\\r\\n function getAssetPriceFromConverter(ITetuConverter converter, address token) external view returns (uint) {\\r\\n return AppLib._getPriceOracle(converter).getAssetPrice(token);\\r\\n }\\r\\n\\r\\n /// @notice Try to find zero amount\\r\\n /// @return True if {amounts_} array contains zero amount\\r\\n function findZeroAmount(uint[] memory amounts_) internal pure returns (bool) {\\r\\n uint len = amounts_.length;\\r\\n for (uint i = 0; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (amounts_[i] == 0) return true;\\r\\n }\\r\\n return false;\\r\\n }\\r\\n//endregion ----------------------------------------- MAIN LOGIC\\r\\n\\r\\n//region -------------------------------------------- Cover loss, send profit to insurance\\r\\n /// @notice Send given {amount} of {asset} (== underlying) to the insurance\\r\\n /// @param totalAssets_ Total strategy balance = balance of underlying + current invested assets amount\\r\\n /// @param balance Current balance of the underlying\\r\\n /// @return sentAmount Amount of underlying sent to the insurance\\r\\n /// @return unsentAmount Missed part of the {amount} that were not sent to the insurance\\r\\n function sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) external returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n return _sendToInsurance(asset, amount, splitter, totalAssets_, balance);\\r\\n }\\r\\n\\r\\n function _sendToInsurance(address asset, uint amount, address splitter, uint totalAssets_, uint balance) internal returns (\\r\\n uint sentAmount,\\r\\n uint unsentAmount\\r\\n ) {\\r\\n uint amountToSend = Math.min(amount, balance);\\r\\n if (amountToSend != 0) {\\r\\n // max amount that can be send to insurance is limited by PRICE_CHANGE_PROFIT_TOLERANCE\\r\\n\\r\\n // Amount limitation should be implemented in the same way as in StrategySplitterV2._coverLoss\\r\\n // Revert or cut amount in both cases\\r\\n\\r\\n require(totalAssets_ != 0, AppErrors.ZERO_BALANCE);\\r\\n amountToSend = Math.min(amountToSend, PRICE_CHANGE_PROFIT_TOLERANCE * totalAssets_ / 100_000);\\r\\n //require(amountToSend <= PRICE_CHANGE_PROFIT_TOLERANCE * strategyBalance / 100_000, AppErrors.EARNED_AMOUNT_TOO_HIGH);\\r\\n\\r\\n IERC20(asset).safeTransfer(address(ITetuVaultV2(ISplitter(splitter).vault()).insurance()), amountToSend);\\r\\n }\\r\\n\\r\\n sentAmount = amountToSend;\\r\\n unsentAmount = amount > amountToSend\\r\\n ? amount - amountToSend\\r\\n : 0;\\r\\n\\r\\n emit SendToInsurance(sentAmount, unsentAmount);\\r\\n }\\r\\n\\r\\n function _registerIncome(uint assetBefore, uint assetAfter) internal pure returns (uint earned, uint lost) {\\r\\n if (assetAfter > assetBefore) {\\r\\n earned = assetAfter - assetBefore;\\r\\n } else {\\r\\n lost = assetBefore - assetAfter;\\r\\n }\\r\\n return (earned, lost);\\r\\n }\\r\\n\\r\\n /// @notice Send ProfitToCover to insurance - code fragment of the requirePayAmountBack()\\r\\n /// moved here to reduce size of requirePayAmountBack()\\r\\n /// @param theAsset_ The asset passed from Converter\\r\\n /// @param balanceTheAsset_ Current balance of {theAsset_}\\r\\n /// @param investedAssets_ Value of investedAssets after call fixPriceChange()\\r\\n /// @param earnedByPrices_ ProfitToCover received from fixPriceChange()\\r\\n /// @return balanceTheAssetOut Final balance of {theAsset_} (after sending profit-to-cover to the insurance)\\r\\n function sendProfitGetAssetBalance(\\r\\n address theAsset_,\\r\\n uint balanceTheAsset_,\\r\\n uint investedAssets_,\\r\\n uint earnedByPrices_,\\r\\n IStrategyV3.BaseState storage baseState_\\r\\n ) external returns (\\r\\n uint balanceTheAssetOut\\r\\n ) {\\r\\n balanceTheAssetOut = balanceTheAsset_;\\r\\n if (earnedByPrices_ != 0) {\\r\\n address underlying = baseState_.asset;\\r\\n uint balanceUnderlying = theAsset_ == underlying\\r\\n ? balanceTheAsset_\\r\\n : AppLib.balance(underlying);\\r\\n\\r\\n _sendToInsurance(underlying, earnedByPrices_, baseState_.splitter, investedAssets_ + balanceUnderlying, balanceUnderlying);\\r\\n\\r\\n if (theAsset_ == underlying) {\\r\\n balanceTheAssetOut = AppLib.balance(theAsset_);\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion -------------------------------------------- Cover loss, send profit to insurance\\r\\n\\r\\n//region ---------------------------------------- Setters\\r\\n function checkReinvestThresholdPercentChanged(address controller, uint percent_) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n require(percent_ <= DENOMINATOR, StrategyLib.WRONG_VALUE);\\r\\n emit ReinvestThresholdPercentChanged(percent_);\\r\\n }\\r\\n\\r\\n function checkLiquidationThresholdChanged(address controller, address token, uint amount) external {\\r\\n StrategyLib.onlyOperators(controller);\\r\\n emit LiquidationThresholdChanged(token, amount);\\r\\n }\\r\\n//endregion ---------------------------------------- Setters\\r\\n\\r\\n//region ---------------------------------------- Withdraw helpers\\r\\n /// @notice Get amount of assets that we expect to receive after withdrawing\\r\\n /// ratio = amount-LP-tokens-to-withdraw / total-amount-LP-tokens-in-pool\\r\\n /// @param reserves_ Reserves of the {poolAssets_}, same order, same length (we don't check it)\\r\\n /// The order of tokens should be same as in {_depositorPoolAssets()},\\r\\n /// one of assets must be {asset_}\\r\\n /// @param liquidityAmount_ Amount of LP tokens that we are going to withdraw\\r\\n /// @param totalSupply_ Total amount of LP tokens in the depositor\\r\\n /// @return withdrawnAmountsOut Expected withdrawn amounts (decimals == decimals of the tokens)\\r\\n function getExpectedWithdrawnAmounts(\\r\\n uint[] memory reserves_,\\r\\n uint liquidityAmount_,\\r\\n uint totalSupply_\\r\\n ) internal pure returns (\\r\\n uint[] memory withdrawnAmountsOut\\r\\n ) {\\r\\n uint ratio = totalSupply_ == 0\\r\\n ? 0\\r\\n : (liquidityAmount_ >= totalSupply_\\r\\n ? 1e18\\r\\n : 1e18 * liquidityAmount_ / totalSupply_\\r\\n );\\r\\n\\r\\n uint len = reserves_.length;\\r\\n withdrawnAmountsOut = new uint[](len);\\r\\n\\r\\n if (ratio != 0) {\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n withdrawnAmountsOut[i] = reserves_[i] * ratio / 1e18;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate expected amount of the main asset after withdrawing\\r\\n /// @param withdrawnAmounts_ Expected amounts to be withdrawn from the pool\\r\\n /// @param amountsToConvert_ Amounts on balance initially available for the conversion\\r\\n /// @return amountsOut Expected amounts of the main asset received after conversion withdrawnAmounts+amountsToConvert\\r\\n function getExpectedAmountMainAsset(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter,\\r\\n uint[] memory withdrawnAmounts_,\\r\\n uint[] memory amountsToConvert_\\r\\n ) internal returns (\\r\\n uint[] memory amountsOut\\r\\n ) {\\r\\n uint len = tokens.length;\\r\\n amountsOut = new uint[](len);\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n amountsOut[i] = withdrawnAmounts_[i];\\r\\n } else {\\r\\n uint amount = withdrawnAmounts_[i] + amountsToConvert_[i];\\r\\n if (amount != 0) {\\r\\n (amountsOut[i],) = converter.quoteRepay(address(this), tokens[indexAsset], tokens[i], amount);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return amountsOut;\\r\\n }\\r\\n\\r\\n /// @notice Add {withdrawnAmounts} to {amountsToConvert}, calculate {expectedAmountMainAsset}\\r\\n /// @param amountsToConvert Amounts of {tokens} to be converted, they are located on the balance before withdraw\\r\\n /// @param withdrawnAmounts Amounts of {tokens} that were withdrew from the pool\\r\\n function postWithdrawActions(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n\\r\\n uint[] memory reservesBeforeWithdraw,\\r\\n uint liquidityAmountWithdrew,\\r\\n uint totalSupplyBeforeWithdraw,\\r\\n\\r\\n uint[] memory amountsToConvert,\\r\\n uint[] memory withdrawnAmounts\\r\\n ) external returns (\\r\\n uint[] memory expectedMainAssetAmounts,\\r\\n uint[] memory _amountsToConvert\\r\\n ) {\\r\\n // estimate expected amount of assets to be withdrawn\\r\\n uint[] memory expectedWithdrawAmounts = getExpectedWithdrawnAmounts(\\r\\n reservesBeforeWithdraw,\\r\\n liquidityAmountWithdrew,\\r\\n totalSupplyBeforeWithdraw\\r\\n );\\r\\n\\r\\n // from received amounts after withdraw calculate how much we receive from converter for them in terms of the underlying asset\\r\\n expectedMainAssetAmounts = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n expectedWithdrawAmounts,\\r\\n amountsToConvert\\r\\n );\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n amountsToConvert[i] += withdrawnAmounts[i];\\r\\n }\\r\\n\\r\\n return (expectedMainAssetAmounts, amountsToConvert);\\r\\n }\\r\\n\\r\\n /// @notice return {withdrawnAmounts} with zero values and expected amount calculated using {amountsToConvert_}\\r\\n function postWithdrawActionsEmpty(\\r\\n ITetuConverter converter,\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory amountsToConvert_\\r\\n ) external returns (\\r\\n uint[] memory expectedAmountsMainAsset\\r\\n ) {\\r\\n expectedAmountsMainAsset = getExpectedAmountMainAsset(\\r\\n tokens,\\r\\n indexAsset,\\r\\n converter,\\r\\n // there are no withdrawn amounts\\r\\n new uint[](tokens.length), // array with all zero values\\r\\n amountsToConvert_\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount earned after withdraw. Withdraw cannot produce income, so we send all\\r\\n /// earned amount to insurance. Also we send to the insurance earned-by-prices-amount here.\\r\\n /// @dev Amount for the insurance is sent from the balance, so the sending doesn't change invested assets.\\r\\n /// @param asset Underlying\\r\\n /// @param investedAssets_ Invested assets amount at the moment of withdrawing start\\r\\n /// @param balanceBefore Balance of the underlying at the moment of withdrawing start\\r\\n /// @param earnedByPrices_ Amount of underlying earned because of price changes, it should be send to the insurance.\\r\\n /// @param updatedInvestedAssets_ Invested assets amount after withdrawing\\r\\n /// @return amountSentToInsurance Total amount sent to the insurance in result.\\r\\n function calculateIncomeAfterWithdraw(\\r\\n address splitter,\\r\\n address asset,\\r\\n uint investedAssets_,\\r\\n uint balanceBefore,\\r\\n uint earnedByPrices_,\\r\\n uint updatedInvestedAssets_\\r\\n ) external returns (uint amountSentToInsurance, uint strategyLoss) {\\r\\n uint balanceAfterWithdraw = AppLib.balance(asset);\\r\\n\\r\\n // we need to compensate difference if during withdraw we lost some assets\\r\\n // also we should send earned amounts to the insurance\\r\\n // it's too dangerous to earn money on withdraw, we can move share price\\r\\n // in the case of \\\"withdraw almost all\\\" share price can be changed significantly\\r\\n // so, it's safer to transfer earned amount to the insurance\\r\\n // earned can exceeds earnedByPrices_\\r\\n // but if earned < earnedByPrices_ it means that we compensate a part of losses from earned-by-prices.\\r\\n uint earned;\\r\\n (earned, strategyLoss) = _registerIncome(\\r\\n AppLib.sub0(investedAssets_ + balanceBefore, earnedByPrices_),\\r\\n updatedInvestedAssets_ + balanceAfterWithdraw\\r\\n );\\r\\n\\r\\n if (earned != earnedByPrices_) {\\r\\n emit OnEarningOnWithdraw(earned, earnedByPrices_);\\r\\n }\\r\\n\\r\\n if (earned != 0) {\\r\\n (amountSentToInsurance,) = _sendToInsurance(\\r\\n asset,\\r\\n earned,\\r\\n splitter,\\r\\n investedAssets_ + balanceBefore,\\r\\n balanceAfterWithdraw\\r\\n );\\r\\n }\\r\\n\\r\\n return (amountSentToInsurance, strategyLoss);\\r\\n }\\r\\n//endregion ------------------------------------- Withdraw helpers\\r\\n\\r\\n//region---------------------------------------- calcInvestedAssets\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) external returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n return _calcInvestedAssets(tokens, depositorQuoteExitAmountsOut, indexAsset, converter_, makeCheckpoint_);\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount we will receive when we withdraw all from pool\\r\\n /// @dev This is writable function because we need to update current balances in the internal protocols.\\r\\n /// @param indexAsset Index of the underlying (main asset) in {tokens}\\r\\n /// @param makeCheckpoint_ True - call IBookkeeper.checkpoint in the converter\\r\\n /// @return amountOut Invested asset amount under control (in terms of underlying)\\r\\n /// @return prices Asset prices in USD, decimals 18\\r\\n /// @return decs 10**decimals\\r\\n function _calcInvestedAssets(\\r\\n address[] memory tokens,\\r\\n uint[] memory depositorQuoteExitAmountsOut,\\r\\n uint indexAsset,\\r\\n ITetuConverter converter_,\\r\\n bool makeCheckpoint_\\r\\n ) internal returns (\\r\\n uint amountOut,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) {\\r\\n CalcInvestedAssetsLocal memory v;\\r\\n v.len = tokens.length;\\r\\n v.asset = tokens[indexAsset];\\r\\n\\r\\n // calculate prices, decimals\\r\\n (prices, decs) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(converter_), tokens, v.len);\\r\\n\\r\\n // A debt is registered below if we have X amount of asset, need to pay Y amount of the asset and X < Y\\r\\n // In this case: debt = Y - X, the order of tokens is the same as in {tokens} array\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n // Current strategy balance of main asset is not taken into account here because it's add by splitter\\r\\n amountOut += depositorQuoteExitAmountsOut[i];\\r\\n } else {\\r\\n v.token = tokens[i];\\r\\n // possible reverse debt: collateralAsset = tokens[i], borrowAsset = underlying\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (uint toPay, uint collateral) = converter_.getDebtAmountCurrent(address(this), v.token, v.asset, false);\\r\\n if (amountOut < toPay) {\\r\\n setDebt(v, indexAsset, toPay);\\r\\n } else {\\r\\n amountOut -= toPay;\\r\\n }\\r\\n\\r\\n // available amount to repay\\r\\n uint toRepay = collateral + IERC20(v.token).balanceOf(address(this)) + depositorQuoteExitAmountsOut[i];\\r\\n\\r\\n // direct debt: collateralAsset = underlying, borrowAsset = tokens[i]\\r\\n // investedAssets is calculated using exact debts, debt-gaps are not taken into account\\r\\n (toPay, collateral) = converter_.getDebtAmountCurrent(address(this), v.asset, v.token, false);\\r\\n amountOut += collateral;\\r\\n\\r\\n if (toRepay >= toPay) {\\r\\n amountOut += (toRepay - toPay) * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n } else {\\r\\n // there is not enough amount to pay the debt\\r\\n // let's register a debt and try to resolve it later below\\r\\n setDebt(v, i, toPay - toRepay);\\r\\n }\\r\\n }\\r\\n }\\r\\n if (v.debts.length == v.len) {\\r\\n // we assume here, that it would be always profitable to save collateral\\r\\n // f.e. if there is not enough amount of USDT on our balance and we have a debt in USDT,\\r\\n // it's profitable to change any available asset to USDT, pay the debt and return the collateral back\\r\\n for (uint i; i < v.len; i = AppLib.uncheckedInc(i)) {\\r\\n if (v.debts[i] == 0) continue;\\r\\n\\r\\n // estimatedAssets should be reduced on the debt-value\\r\\n // this estimation is approx and do not count price impact on the liquidation\\r\\n // we will able to count the real output only after withdraw process\\r\\n uint debtInAsset = v.debts[i] * prices[i] * decs[indexAsset] / prices[indexAsset] / decs[i];\\r\\n if (debtInAsset > amountOut) {\\r\\n // The debt is greater than we can pay. We shouldn't try to pay the debt in this case\\r\\n amountOut = 0;\\r\\n } else {\\r\\n amountOut -= debtInAsset;\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n if (makeCheckpoint_) {\\r\\n _callCheckpoint(tokens, converter_);\\r\\n }\\r\\n\\r\\n return (amountOut, prices, decs);\\r\\n }\\r\\n\\r\\n /// @notice Make new checkpoint in converter's bookkeeper\\r\\n /// As results, a next call of checkpoint will return amount of increases to debts (\\\"deltas\\\")\\r\\n /// since current moment up to the moment of the next call (we need such deltas in _fixPriceChanges only)\\r\\n function _callCheckpoint(address[] memory tokens, ITetuConverter converter_) internal returns (\\r\\n uint[] memory deltaGains,\\r\\n uint[] memory deltaLosses\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter_.controller()).bookkeeper());\\r\\n return a.checkpoint(tokens);\\r\\n }\\r\\n\\r\\n /// @notice Lazy initialization of v.debts, add {value} to {v.debts[index]}\\r\\n function setDebt(CalcInvestedAssetsLocal memory v, uint index, uint value) pure internal {\\r\\n if (v.debts.length == 0) {\\r\\n // lazy initialization\\r\\n v.debts = new uint[](v.len);\\r\\n }\\r\\n\\r\\n // to pay the following amount we need to swap some other asset at first\\r\\n v.debts[index] += value;\\r\\n }\\r\\n\\r\\n /// @notice Calculate the token amounts for deposit and amount of loss (as old-total-asset - new-total-asset)\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n /// @return loss New total assets - old total assets\\r\\n /// @return tokenAmounts Balances of the token A and token B.\\r\\n /// If any balance is zero it's not possible to enter to the pool, so return empty array (len 0)\\r\\n function getTokenAmountsPair(\\r\\n ITetuConverter converter,\\r\\n uint totalAssets,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint[2] calldata liquidationThresholdsAB\\r\\n ) external returns (\\r\\n uint loss,\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n tokenAmounts = new uint[](2);\\r\\n tokenAmounts[0] = AppLib.balance(tokenA);\\r\\n tokenAmounts[1] = AppLib.balance(tokenB);\\r\\n\\r\\n address[] memory tokens = new address[](2);\\r\\n tokens[0] = tokenA;\\r\\n tokens[1] = tokenB;\\r\\n\\r\\n uint[] memory amounts = new uint[](2);\\r\\n amounts[0] = tokenAmounts[0];\\r\\n\\r\\n (uint newTotalAssets,,) = _calcInvestedAssets(tokens, amounts, 0, converter, true);\\r\\n return (\\r\\n newTotalAssets < totalAssets\\r\\n ? totalAssets - newTotalAssets\\r\\n : 0,\\r\\n (tokenAmounts[0] < liquidationThresholdsAB[0] || tokenAmounts[1] < liquidationThresholdsAB[1])\\r\\n ? new uint[](0)\\r\\n : tokenAmounts\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Swap can give us more amount out than expected, so we will receive increasing of share price.\\r\\n /// To prevent it, we need to send exceeded amount to insurance,\\r\\n /// but it's too expensive to make such transfer at the end of withdrawAggByStep.\\r\\n /// So, we postpone sending the profit until the next call of fixPriceChange\\r\\n /// by manually setting investedAssets equal to the oldTotalAssets\\r\\n /// @dev If profitToCover was sent only partly, we will postpone sending of remain amount up to the next call\\r\\n /// of fixPriceChange in same manner\\r\\n /// @param oldTotalAssets Total asset at the moment after last call of fixPriceChange,\\r\\n /// decreased on the value of profitToCover.\\r\\n function fixTooHighInvestedAssets(\\r\\n address asset_,\\r\\n uint oldTotalAssets,\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs_\\r\\n ) external {\\r\\n uint balance = IERC20(asset_).balanceOf(address(this));\\r\\n uint newTotalAssets = csbs_.investedAssets + balance;\\r\\n\\r\\n if (oldTotalAssets < newTotalAssets) {\\r\\n // total asset was increased (i.e. because of too profitable swaps)\\r\\n // this increment will increase share price\\r\\n // we should send added amount to insurance to avoid share price change\\r\\n // anyway, it's too expensive to do it here\\r\\n // so, we postpone sending the profit until the next call of fixPriceChange\\r\\n if (oldTotalAssets > balance) {\\r\\n csbs_.investedAssets = oldTotalAssets - balance;\\r\\n }\\r\\n }\\r\\n }\\r\\n//endregion------------------------------------- calcInvestedAssets\\r\\n\\r\\n//region ------------------------------------------------------- Bookkeeper logic\\r\\n /// @notice Make checkpoint (it's writable function) and calculate total cost of the deltas in terms of the {asset}\\r\\n /// @param tokens Full list of tokens that can be used as collateral/borrow asset by the current strategy\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return increaseToDebt Total increase-to-debt since previous checkpoint [in underlying]\\r\\n function _getIncreaseToDebt(\\r\\n address[] memory tokens,\\r\\n uint indexAsset,\\r\\n uint[] memory prices,\\r\\n uint[] memory decs,\\r\\n ITetuConverter converter\\r\\n ) internal returns (\\r\\n int increaseToDebt\\r\\n ) {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint[] memory deltaGains, uint[] memory deltaLosses) = a.checkpoint(tokens);\\r\\n\\r\\n uint len = tokens.length;\\r\\n for (uint i; i < len; i = AppLib.uncheckedInc(i)) {\\r\\n if (i == indexAsset) {\\r\\n increaseToDebt -= int(deltaGains[i]);\\r\\n increaseToDebt += int(deltaLosses[i]);\\r\\n } else {\\r\\n increaseToDebt += (int(deltaLosses[i]) - int(deltaGains[i]))\\r\\n * int(prices[i]) * int(decs[indexAsset]) / int(prices[indexAsset]) / int(decs[i]);\\r\\n }\\r\\n }\\r\\n emit OnIncreaseDebtToInsurance(tokens, deltaGains, deltaLosses, prices, increaseToDebt);\\r\\n\\r\\n return increaseToDebt;\\r\\n }\\r\\n\\r\\n /// @notice Register income and cover possible loss after price changing, emit FixPriceChanges\\r\\n /// @param investedAssetsBefore Currently stored value of _csbs.investedAssets\\r\\n /// @param investedAssetsAfter Actual value of invested assets calculated at the current moment\\r\\n /// @param increaseToDebt The amount by which the total loan debts increased for the selected period\\r\\n /// @return earned Amount earned because of price changing\\r\\n function _coverLossAfterPriceChanging(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n uint investedAssetsBefore,\\r\\n uint investedAssetsAfter,\\r\\n int increaseToDebt,\\r\\n IStrategyV3.BaseState storage baseState\\r\\n ) internal returns (uint earned) {\\r\\n int debtToInsurance0 = csbs.debtToInsurance;\\r\\n if (investedAssetsAfter > investedAssetsBefore) {\\r\\n earned = investedAssetsAfter - investedAssetsBefore;\\r\\n if (increaseToDebt != 0) {\\r\\n // Earned amount will be send to the insurance later.\\r\\n // Probably it can be reduced by same limitations as {lost} amount below\\r\\n // and so, it will be necessary to decrease increaseToDebt proportionally.\\r\\n // For simplicity, we increase debtToInsurance on full increaseToDebt always\\r\\n // in assumption, that such profits are always low.\\r\\n csbs.debtToInsurance += increaseToDebt;\\r\\n emit ChangeDebtToInsuranceOnProfit(debtToInsurance0, increaseToDebt);\\r\\n }\\r\\n } else {\\r\\n uint lost = investedAssetsBefore - investedAssetsAfter;\\r\\n if (lost != 0) {\\r\\n uint totalAsset = investedAssetsAfter + IERC20(baseState.asset).balanceOf(address(this));\\r\\n (uint lossToCover, uint lossUncovered) = _getSafeLossToCover(lost, totalAsset);\\r\\n\\r\\n if (lossUncovered != 0) {\\r\\n // we need to cover lost-amount, but this amount is too high and will produce revert in the splitter\\r\\n // so, we will cover only part of {lost} and leave other part uncovered.\\r\\n emit UncoveredLoss(lossToCover, lossUncovered, investedAssetsBefore, investedAssetsAfter);\\r\\n }\\r\\n\\r\\n // if we compensate lost only partially, we reduce both amounts \\\"from prices\\\" and \\\"from debts\\\" proportionally\\r\\n _coverLossAndCheckResults(csbs, baseState.splitter, lossToCover, increaseToDebt * int(lossToCover) / int(lost));\\r\\n\\r\\n }\\r\\n }\\r\\n\\r\\n emit FixPriceChanges(\\r\\n investedAssetsBefore,\\r\\n investedAssetsAfter,\\r\\n debtToInsurance0,\\r\\n csbs.debtToInsurance,\\r\\n increaseToDebt\\r\\n );\\r\\n return earned;\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n /// If the loss were covered only partially, emit {NotEnoughInsurance}\\r\\n function coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover\\r\\n ) external {\\r\\n _coverLossAndCheckResults(csbs, splitter, lossToCover, int(lossToCover));\\r\\n }\\r\\n\\r\\n /// @notice Call coverPossibleStrategyLoss, covered loss will be sent to vault.\\r\\n function _coverLossAndCheckResults(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n address splitter,\\r\\n uint lossToCover,\\r\\n int debtToInsuranceInc\\r\\n ) internal {\\r\\n address asset = ISplitter(splitter).asset();\\r\\n address vault = ISplitter(splitter).vault();\\r\\n\\r\\n uint balanceBefore = IERC20(asset).balanceOf(vault);\\r\\n ISplitter(splitter).coverPossibleStrategyLoss(0, lossToCover);\\r\\n uint balanceAfter = IERC20(asset).balanceOf(vault);\\r\\n\\r\\n uint delta = AppLib.sub0(balanceAfter, balanceBefore);\\r\\n uint uncovered = AppLib.sub0(lossToCover, delta);\\r\\n debtToInsuranceInc = lossToCover == 0\\r\\n ? int(0)\\r\\n : debtToInsuranceInc * int(lossToCover - uncovered) / int(lossToCover);\\r\\n\\r\\n if (debtToInsuranceInc != 0) {\\r\\n csbs.debtToInsurance += debtToInsuranceInc;\\r\\n }\\r\\n\\r\\n // we don't add uncovered amount to the debts to the insurance\\r\\n emit OnCoverLoss(lossToCover, debtToInsuranceInc, delta, uncovered);\\r\\n }\\r\\n\\r\\n /// @notice Cut loss-value to safe value that doesn't produce revert inside splitter\\r\\n function _getSafeLossToCover(uint loss, uint totalAssets_) internal pure returns (\\r\\n uint lossToCover,\\r\\n uint lossUncovered\\r\\n ) {\\r\\n // see StrategySplitterV2._declareStrategyIncomeAndCoverLoss, _coverLoss implementations\\r\\n lossToCover = Math.min(loss, ConverterStrategyBaseLib2.HARDWORK_LOSS_TOLERANCE * totalAssets_ / 100_000);\\r\\n lossUncovered = AppLib.sub0(loss, lossToCover);\\r\\n }\\r\\n\\r\\n /// @notice Calculate profit/loss happened because of price changing.\\r\\n /// Try to cover the loss, send the profit to the insurance.\\r\\n /// Increment debt to insurance on amount of increase of the debts.\\r\\n /// @param amountsInPool Amount of tokens that can be received from the pool after withdrawing all liquidity.\\r\\n /// The order of tokens is same as in the {tokens}\\r\\n /// @param tokens Result of {_depositorPoolAssets}\\r\\n /// @param indexAsset Index of the underlying in {tokens}\\r\\n /// @return investedAssetsOut Updated value of {csbs.investedAssets}\\r\\n /// @return earnedOut Profit that was received because of price changes. It should be sent back to insurance.\\r\\n function fixPriceChanges(\\r\\n IConverterStrategyBase.ConverterStrategyBaseState storage csbs,\\r\\n IStrategyV3.BaseState storage baseState,\\r\\n uint[] memory amountsInPool,\\r\\n address[] memory tokens,\\r\\n uint indexAsset\\r\\n ) external returns (\\r\\n uint investedAssetsOut,\\r\\n uint earnedOut\\r\\n ) {\\r\\n ITetuConverter converter = csbs.converter;\\r\\n uint investedAssetsBefore = csbs.investedAssets;\\r\\n\\r\\n uint[] memory prices;\\r\\n uint[] memory decs;\\r\\n\\r\\n (investedAssetsOut, prices, decs) = _calcInvestedAssets(tokens, amountsInPool, indexAsset, converter, false);\\r\\n csbs.investedAssets = investedAssetsOut;\\r\\n\\r\\n int increaseToDebt = _getIncreaseToDebt(tokens, indexAsset, prices, decs, converter);\\r\\n earnedOut = _coverLossAfterPriceChanging(csbs, investedAssetsBefore, investedAssetsOut, increaseToDebt, baseState);\\r\\n }\\r\\n\\r\\n /// @notice Register amounts received for supplying collaterals and amount paid for the debts\\r\\n /// for the current period (a new period is started after each hardwork operation)\\r\\n function registerBorrowResults(ITetuConverter converter, address asset) external {\\r\\n IBookkeeper a = IBookkeeper(IConverterController(converter.controller()).bookkeeper());\\r\\n (uint gains, uint losses) = a.startPeriod(asset);\\r\\n if (gains != 0 && losses != 0) {\\r\\n emit BorrowResults(gains, losses);\\r\\n }\\r\\n }\\r\\n//endregion ------------------------------------------------------- Bookkeeper logic\\r\\n\\r\\n\\r\\n}\\r\\n\\r\\n\",\"keccak256\":\"0xbf108a509285156685b75ae591c421fc9b514e6011fd95f30ec4bfa13dd9f1d5\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/ITetuLiquidator.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"../../interfaces/IPoolProportionsProvider.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\n/// @dev The library contains quoteWithdrawStep/withdrawStep-related logic\\r\\nlibrary PairBasedStrategyLib {\\r\\n //region ------------------------------------------------ Constants\\r\\n uint internal constant _ASSET_LIQUIDATION_SLIPPAGE = 300;\\r\\n /// @notice In all functions below array {token} contains underlying at the first position\\r\\n uint internal constant IDX_ASSET = 0;\\r\\n /// @notice In all functions below array {token} contains not-underlying at the second position\\r\\n uint internal constant IDX_TOKEN = 1;\\r\\n\\r\\n uint internal constant IDX_SWAP_1 = 0;\\r\\n uint internal constant IDX_REPAY_1 = 1;\\r\\n uint internal constant IDX_SWAP_2 = 2;\\r\\n uint internal constant IDX_REPAY_2 = 3;\\r\\n\\r\\n /// @notice A gap to reduce AmountToSwap calculated inside quoteWithdrawByAgg, [0...100_000]\\r\\n uint public constant GAP_AMOUNT_TO_SWAP = 100;\\r\\n\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED = 1;\\r\\n /// @notice Enter to the pool at the end of withdrawByAggStep only if full withdrawing has been completed\\r\\n uint public constant ENTRY_TO_POOL_IS_ALLOWED_IF_COMPLETED = 2;\\r\\n\\r\\n /// @notice Fuse thresholds are set as array: [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// If the price falls below LOWER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices raises back and reaches LOWER_LIMIT_OFF, the fuse is turned OFF\\r\\n /// In the same way, if the price raises above UPPER_LIMIT_ON the fuse is turned ON\\r\\n /// When the prices falls back and reaches UPPER_LIMIT_OFF, the fuse is turned OFF\\r\\n ///\\r\\n /// Example: [0.9, 0.92, 1.08, 1.1]\\r\\n /// Price falls below 0.9 - fuse is ON. Price rises back up to 0.92 - fuse is OFF.\\r\\n /// Price raises more and reaches 1.1 - fuse is ON again. Price falls back and reaches 1.08 - fuse OFF again.\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_ON = 0;\\r\\n uint public constant FUSE_IDX_LOWER_LIMIT_OFF = 1;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_ON = 2;\\r\\n uint public constant FUSE_IDX_UPPER_LIMIT_OFF = 3;\\r\\n\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_A = 0;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_TOKEN_B = 1;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_POOL = 2;\\r\\n uint public constant IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER = 3;\\r\\n\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_TICK_SPACING = 0;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_LOWER_TICK = 1;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_UPPER_TICK = 2;\\r\\n uint public constant IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE = 3;\\r\\n\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY = 0;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_FUSE_STATUS = 1;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_0 = 2;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE = 3;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 = 4;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_1 = 5;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_2 = 6;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_THRESHOLD_3 = 7;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_1 = 8;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_2 = 9;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_3 = 10;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_RESERVED_4 = 11;\\r\\n uint public constant IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP = 12;\\r\\n\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL = 0;\\r\\n uint public constant IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS = 1;\\r\\n\\r\\n /// @notice 1inch router V5 (Polygon, Base)\\r\\n address internal constant ONEINCH = 0x1111111254EEB25477B68fb85Ed929f73A960582;\\r\\n /// @notice OpenOceanExchangeProxy (Polygon and many other chains)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN = 0x6352a56caadC4F1E25CD6c75970Fa768A3304e64;\\r\\n /// @notice OpenOceanExchangeProxy (zkEVM)\\r\\n /// @dev See https://docs.openocean.finance/dev/contracts-of-chains\\r\\n address internal constant OPENOCEAN_ZKEVM = 0x6dd434082EAB5Cd134B33719ec1FF05fE985B97b;\\r\\n\\r\\n string public constant UNKNOWN_SWAP_ROUTER = \\\"PBS-1 Unknown router\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"PBS-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"PBS-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"PBS-5 Incorrect asset\\\";\\r\\n\\r\\n //endregion ------------------------------------------------ Constants\\r\\n\\r\\n //region ------------------------------------------------ Data types\\r\\n /// @notice The fuse is triggered when the price rises above or falls below the limit 1.\\r\\n /// If the fuse was triggered, all assets are withdrawn from the pool on the strategy balance.\\r\\n /// Then all debts should be closed and all assets should be converted to underlying.\\r\\n /// The fuse is turned off automatically when the price falls below or rises above the limit 2\\r\\n /// and all assets are deposited back to the pool.\\r\\n enum FuseStatus {\\r\\n /// @notice Fuse is not used at all\\r\\n FUSE_DISABLED_0,\\r\\n /// @notice Fuse is not triggered, assets are deposited to the pool\\r\\n FUSE_OFF_1,\\r\\n /// @notice Fuse was triggered by lower limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_LOWER_LIMIT_2,\\r\\n /// @notice Fuse was triggered by upper limit, assets was withdrawn from the pool, but active debts can exist\\r\\n FUSE_ON_UPPER_LIMIT_3\\r\\n }\\r\\n\\r\\n struct SwapByAggParams {\\r\\n bool useLiquidator;\\r\\n address tokenToSwap;\\r\\n /// @notice Aggregator to make swap\\r\\n /// It is 0 if useLiquidator is true\\r\\n /// It can be equal to address of liquidator if we use liquidator as aggregator (in tests)\\r\\n address aggregator;\\r\\n uint amountToSwap;\\r\\n /// @notice Swap-data prepared off-chain (route, amounts, etc). 0 - use liquidator to make swap\\r\\n bytes swapData;\\r\\n }\\r\\n\\r\\n struct GetAmountToRepay2Local {\\r\\n uint x;\\r\\n uint y;\\r\\n uint c0;\\r\\n uint b0;\\r\\n uint alpha;\\r\\n int b;\\r\\n }\\r\\n\\r\\n struct FuseStateParams {\\r\\n FuseStatus status;\\r\\n /// @notice Price thresholds [LOWER_LIMIT_ON, LOWER_LIMIT_OFF, UPPER_LIMIT_ON, UPPER_LIMIT_OFF]\\r\\n /// @dev see PairBasedStrategyLib.FUSE_IDX_XXX\\r\\n uint[4] thresholds;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[4] __gap;\\r\\n }\\r\\n //endregion ------------------------------------------------ Data types\\r\\n\\r\\n //region ------------------------------------------------ Events\\r\\n event FuseStatusChanged(uint fuseStatus);\\r\\n event NewFuseThresholds(uint[4] newFuseThresholds);\\r\\n event SwapByAgg(\\r\\n uint amountToSwap,\\r\\n uint amountIn,\\r\\n uint amountOut,\\r\\n uint expectedAmountOut,\\r\\n address aggregator,\\r\\n address assetIn,\\r\\n address assetOut\\r\\n );\\r\\n //endregion ------------------------------------------------ Events\\r\\n\\r\\n //region ------------------------------------------------ External withdraw functions\\r\\n\\r\\n /// @notice Get info for the swap that will be made on the next call of {withdrawStep}\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// Value type(uint).max means that the proportions should be read from the pool.\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @param amountsFromPool Amounts of {tokens} that will be received from the pool before calling withdraw\\r\\n /// @return tokenToSwap Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @return amountToSwap Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// This amount is NOT reduced on {GAP_AMOUNT_TO_SWAP}, it should be reduced after the call if necessary.\\r\\n function quoteWithdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n uint[] memory amountsFromPool,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: amountsFromPool,\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n return _quoteWithdrawStep(p);\\r\\n }\\r\\n\\r\\n /// @notice Make withdraw step with 0 or 1 swap only. The step can make one of the following actions:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) final swap leftovers of not-underlying asset\\r\\n /// @param converterLiquidator_ [TetuConverter, TetuLiquidator]\\r\\n /// @param tokens Tokens used by depositor (length == 2: underlying and not-underlying)\\r\\n /// @param liquidationThresholds Liquidation thresholds for the {tokens}\\r\\n /// @param tokenToSwap_ Address of the token that will be swapped on the next swap. 0 - no swap\\r\\n /// @param amountToSwap_ Amount that will be swapped on the next swap. 0 - no swap\\r\\n /// @param aggregator_ Aggregator that should be used for the next swap. 0 - no swap\\r\\n /// @param swapData_ Swap data to be passed to the aggregator on the next swap.\\r\\n /// Swap data contains swap-route, amount and all other required info for the swap.\\r\\n /// Swap data should be prepared on-chain on the base of data received by {quoteWithdrawStep}\\r\\n /// @param useLiquidator_ Use liquidator instead of aggregator.\\r\\n /// Aggregator swaps amount reduced on {GAP_AMOUNT_TO_SWAP}.\\r\\n /// Liquidator doesn't use {GAP_AMOUNT_TO_SWAP}.\\r\\n /// It's allowed to pass liquidator address in {aggregator_} and set {useLiquidator_} to false -\\r\\n /// the liquidator will be used in same way as aggregator in this case.\\r\\n /// @param planKind One of IterationPlanLib.PLAN_XXX\\r\\n /// @param entryDataValues [propNotUnderlying18, entryDataParam]\\r\\n /// propNotUnderlying18 Required proportion of not-underlying for the final swap of leftovers, [0...1e18].\\r\\n /// The leftovers should be swapped to get following result proportions of the assets:\\r\\n /// not-underlying : underlying === propNotUnderlying18 : 1e18 - propNotUnderlying18\\r\\n /// entryDataParam It contains \\\"required-amount-to-reduce-debt\\\" in REPAY-SWAP-REPAY case\\r\\n /// @return completed All debts were closed, leftovers were swapped to the required proportions\\r\\n function withdrawStep(\\r\\n address[2] memory converterLiquidator_,\\r\\n address[] memory tokens,\\r\\n uint[] memory liquidationThresholds,\\r\\n address tokenToSwap_,\\r\\n uint amountToSwap_,\\r\\n address aggregator_,\\r\\n bytes memory swapData_,\\r\\n bool useLiquidator_,\\r\\n uint planKind,\\r\\n uint[2] memory entryDataValues\\r\\n ) external returns (\\r\\n bool completed\\r\\n ){\\r\\n (uint[] memory prices,\\r\\n uint[] memory decs\\r\\n ) = AppLib._getPricesAndDecs(AppLib._getPriceOracle(ITetuConverter(converterLiquidator_[0])), tokens, 2);\\r\\n\\r\\n IterationPlanLib.SwapRepayPlanParams memory p = IterationPlanLib.SwapRepayPlanParams({\\r\\n converter: ITetuConverter(converterLiquidator_[0]),\\r\\n liquidator: ITetuLiquidator(converterLiquidator_[1]),\\r\\n tokens: tokens,\\r\\n liquidationThresholds: liquidationThresholds,\\r\\n propNotUnderlying18: entryDataValues[0] == type(uint).max\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : entryDataValues[0],\\r\\n prices: prices,\\r\\n decs: decs,\\r\\n balanceAdditions: new uint[](2), // 2 = tokens.length\\r\\n planKind: planKind,\\r\\n usePoolProportions: entryDataValues[0] == type(uint).max,\\r\\n entryDataParam: entryDataValues[1]\\r\\n });\\r\\n SwapByAggParams memory aggParams = SwapByAggParams({\\r\\n tokenToSwap: tokenToSwap_,\\r\\n amountToSwap: amountToSwap_,\\r\\n useLiquidator: useLiquidator_,\\r\\n aggregator: aggregator_,\\r\\n swapData: swapData_\\r\\n });\\r\\n return _withdrawStep(p, aggParams);\\r\\n }\\r\\n //endregion ------------------------------------------------ External withdraw functions\\r\\n\\r\\n //region ------------------------------------------------ Fuse functions\\r\\n function setFuseStatus(FuseStateParams storage fuse, FuseStatus status) external {\\r\\n fuse.status = status;\\r\\n emit FuseStatusChanged(uint(status));\\r\\n }\\r\\n\\r\\n function setFuseThresholds(FuseStateParams storage state, uint[4] memory values) external {\\r\\n require(\\r\\n (values[FUSE_IDX_LOWER_LIMIT_ON] == 0 && values[FUSE_IDX_LOWER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_LOWER_LIMIT_ON] <= values[FUSE_IDX_LOWER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n require(\\r\\n (values[FUSE_IDX_UPPER_LIMIT_ON] == 0 && values[FUSE_IDX_UPPER_LIMIT_OFF] == 0)\\r\\n || (values[FUSE_IDX_UPPER_LIMIT_ON] >= values[FUSE_IDX_UPPER_LIMIT_OFF]),\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n if (values[FUSE_IDX_LOWER_LIMIT_ON] != 0 && values[FUSE_IDX_UPPER_LIMIT_ON] != 0) {\\r\\n require(\\r\\n values[FUSE_IDX_UPPER_LIMIT_ON] > values[FUSE_IDX_LOWER_LIMIT_ON],\\r\\n AppErrors.INVALID_VALUE\\r\\n );\\r\\n }\\r\\n state.thresholds = values;\\r\\n emit NewFuseThresholds(values);\\r\\n }\\r\\n\\r\\n function isFuseTriggeredOn(PairBasedStrategyLib.FuseStatus fuseStatus) internal pure returns (bool) {\\r\\n return uint(fuseStatus) > uint(PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n }\\r\\n\\r\\n /// @notice Check if the fuse should be turned ON/OFF\\r\\n /// @param price Current price in the oracle\\r\\n /// @param poolPrice Current price in the pool\\r\\n /// @return needToChange A boolean indicating if the fuse status should be changed\\r\\n /// @return status Exist fuse status or new fuse status (if needToChange is true)\\r\\n function needChangeFuseStatus(FuseStateParams memory fuse, uint price, uint poolPrice) internal pure returns (\\r\\n bool needToChange,\\r\\n FuseStatus status\\r\\n ) {\\r\\n if (fuse.status != FuseStatus.FUSE_DISABLED_0) {\\r\\n if (fuse.status == FuseStatus.FUSE_OFF_1) {\\r\\n // currently fuse is OFF\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n needToChange = true;\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n }\\r\\n } else {\\r\\n if (fuse.status == FuseStatus.FUSE_ON_LOWER_LIMIT_2) {\\r\\n // currently fuse is triggered ON by lower limit\\r\\n if (price >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] && poolPrice >= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON] || poolPrice >= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_ON]) {\\r\\n status = FuseStatus.FUSE_ON_UPPER_LIMIT_3;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // currently fuse is triggered ON by upper limit\\r\\n if (price <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF] && poolPrice <= fuse.thresholds[FUSE_IDX_UPPER_LIMIT_OFF]) {\\r\\n needToChange = true;\\r\\n if (price <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF] || poolPrice <= fuse.thresholds[FUSE_IDX_LOWER_LIMIT_OFF]) {\\r\\n status = FuseStatus.FUSE_ON_LOWER_LIMIT_2;\\r\\n } else {\\r\\n status = FuseStatus.FUSE_OFF_1;\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n return (needToChange, needToChange ? status : fuse.status);\\r\\n }\\r\\n //endregion ------------------------------------------------ Fuse functions\\r\\n\\r\\n //region ------------------------------------------------ Internal helper functions\\r\\n /// @notice Quote amount of the next swap if any.\\r\\n /// Swaps are required if direct-borrow exists OR reverse-borrow exists or not underlying leftovers exist\\r\\n /// Function returns info for first swap only.\\r\\n /// @return tokenToSwap What token should be swapped. Zero address if no swap is required\\r\\n /// @return amountToSwap Amount to swap. Zero if no swap is required.\\r\\n function _quoteWithdrawStep(IterationPlanLib.SwapRepayPlanParams memory p) internal returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n uint indexTokenToSwapPlus1;\\r\\n (indexTokenToSwapPlus1, amountToSwap,) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n if (indexTokenToSwapPlus1 != 0) {\\r\\n tokenToSwap = p.tokens[indexTokenToSwapPlus1 - 1];\\r\\n }\\r\\n return (tokenToSwap, amountToSwap);\\r\\n }\\r\\n\\r\\n /// @notice Make one iteration of withdraw. Each iteration can make 0 or 1 swap only\\r\\n /// We can make only 1 of the following 3 operations per single call:\\r\\n /// 1) repay direct debt 2) repay reverse debt 3) swap leftovers to underlying\\r\\n function _withdrawStep(IterationPlanLib.SwapRepayPlanParams memory p, SwapByAggParams memory aggParams) internal returns (\\r\\n bool completed\\r\\n ) {\\r\\n (uint idxToSwap1, uint amountToSwap, uint idxToRepay1) = IterationPlanLib.buildIterationPlan(\\r\\n [address(p.converter), address(p.liquidator)],\\r\\n p.tokens,\\r\\n p.liquidationThresholds,\\r\\n p.prices,\\r\\n p.decs,\\r\\n p.balanceAdditions,\\r\\n [\\r\\n p.usePoolProportions ? 1 : 0,\\r\\n p.planKind,\\r\\n p.propNotUnderlying18,\\r\\n type(uint).max,\\r\\n IDX_ASSET,\\r\\n IDX_TOKEN,\\r\\n p.entryDataParam\\r\\n ]\\r\\n );\\r\\n\\r\\n bool[4] memory actions = [\\r\\n p.planKind == IterationPlanLib.PLAN_SWAP_ONLY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // swap 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY || p.planKind == IterationPlanLib.PLAN_SWAP_REPAY, // repay 1\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, // swap 2\\r\\n p.planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY // repay 2\\r\\n ];\\r\\n\\r\\n if (idxToSwap1 != 0 && actions[IDX_SWAP_1]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n }\\r\\n\\r\\n if (idxToRepay1 != 0 && actions[IDX_REPAY_1]) {\\r\\n ConverterStrategyBaseLib._repayDebt(\\r\\n p.converter,\\r\\n p.tokens[idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET],\\r\\n p.tokens[idxToRepay1 - 1],\\r\\n IERC20(p.tokens[idxToRepay1 - 1]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n if (idxToSwap1 != 0) {\\r\\n if (actions[IDX_SWAP_2]) {\\r\\n (, p.propNotUnderlying18) = _swap(p, aggParams, idxToSwap1 - 1, idxToSwap1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, amountToSwap);\\r\\n\\r\\n if (actions[IDX_REPAY_2] && idxToRepay1 != 0) {\\r\\n // see calculations inside estimateSwapAmountForRepaySwapRepay\\r\\n // There are two possibilities here:\\r\\n // 1) All collateral asset available on balance was swapped. We need additional repay to get assets in right proportions\\r\\n // 2) Only part of collateral asset was swapped, so assets are already in right proportions. Repay 2 is not needed\\r\\n (uint amountToRepay2, bool borrowInsteadRepay) = _getAmountToRepay2(\\r\\n p,\\r\\n idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET,\\r\\n idxToRepay1 - 1\\r\\n );\\r\\n\\r\\n if (borrowInsteadRepay) {\\r\\n _borrowToProportions(p, idxToRepay1 - 1, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, true);\\r\\n\\r\\n } else if (amountToRepay2 > p.liquidationThresholds[idxToRepay1 - 1]) {\\r\\n _secondRepay(p, idxToRepay1 - 1 == IDX_ASSET ? IDX_TOKEN : IDX_ASSET, idxToRepay1 - 1, amountToRepay2, type(uint).max);\\r\\n }\\r\\n }\\r\\n } else {\\r\\n // leftovers were swapped, there are no debts anymore\\r\\n // the swap can change pool proportions, so probably it's necessary to make additional borrow here\\r\\n if (\\r\\n idxToRepay1 == 0 // there are no debts anymore\\r\\n && p.usePoolProportions // we use proportions from the pool\\r\\n && p.propNotUnderlying18 != 0 && p.propNotUnderlying18 != 1e18 // BorrowLib doesn't allow prop=0\\r\\n ) {\\r\\n _fixLeftoversProportions(p);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // Withdraw is completed on last iteration (no debts, swapping leftovers)\\r\\n return idxToRepay1 == 0;\\r\\n }\\r\\n\\r\\n /// @notice Make final repay in the scheme REPAY-SWAP-REPAY\\r\\n /// Depending on condition the final repay can be made several times or additional borrow can be made\\r\\n /// @param amountToRepay Amount of {indexBorrow} asset that should be repaid\\r\\n /// @param needToRepayPrev Amount-to-repay on previous call of the {_secondRepay}\\r\\n /// This amount should decrease on each step of recursion.\\r\\n /// if it doesn't decrease repay is not successfull and it's useless to continue to call repays\\r\\n /// It can happen if liquidationThreshold has incorrect value (i.t. it's too low or zero)\\r\\n function _secondRepay(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint amountToRepay,\\r\\n uint needToRepayPrev\\r\\n ) internal {\\r\\n // we need to know repaidAmount\\r\\n // we cannot relay on the value returned by _repayDebt because of SCB-710, we need to check balances\\r\\n uint balanceBefore = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n ConverterStrategyBaseLib._repayDebt(p.converter, p.tokens[indexCollateral], p.tokens[indexBorrow], amountToRepay);\\r\\n uint balanceAfter = IERC20(p.tokens[indexBorrow]).balanceOf(address(this));\\r\\n\\r\\n uint repaidAmount = balanceBefore > balanceAfter\\r\\n ? balanceBefore - balanceAfter\\r\\n : 0;\\r\\n\\r\\n if (repaidAmount < amountToRepay && amountToRepay - repaidAmount > p.liquidationThresholds[indexBorrow]) {\\r\\n // repaidAmount is less than expected\\r\\n // we need to make additional borrow OR probably make one more repay\\r\\n // repaidAmount can be less amountToRepay2 even if there is still opened debt, see SCB-777\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexCollateral], p.tokens[indexBorrow], true);\\r\\n if (\\r\\n needToRepay > p.liquidationThresholds[indexBorrow]\\r\\n && needToRepay < needToRepayPrev // amount of debt was reduced on prev iteration of recursion\\r\\n ) {\\r\\n // more repays are required\\r\\n _secondRepay(p, indexCollateral, indexBorrow, amountToRepay - repaidAmount, needToRepay);\\r\\n } else {\\r\\n _borrowToProportions(p, indexBorrow, indexCollateral, false);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Set balances to right proportions using borrow\\r\\n /// (it can be necessary if propNotUnderlying18 was changed after swap)\\r\\n function _fixLeftoversProportions(IterationPlanLib.SwapRepayPlanParams memory p) internal {\\r\\n uint balanceAsset = IERC20(p.tokens[IDX_ASSET]).balanceOf(address(this));\\r\\n uint balanceToken = IERC20(p.tokens[IDX_TOKEN]).balanceOf(address(this));\\r\\n (uint targetAssets,\\r\\n uint targetTokens\\r\\n ) = IterationPlanLib._getTargetAmounts(p.prices, p.decs, balanceAsset, balanceToken, p.propNotUnderlying18, IDX_ASSET, IDX_TOKEN);\\r\\n\\r\\n if (balanceAsset > targetAssets) {\\r\\n if (balanceAsset - targetAssets > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_ASSET, IDX_TOKEN, balanceAsset, balanceToken, true);\\r\\n }\\r\\n } else if (balanceToken > targetTokens) {\\r\\n if (balanceToken - targetTokens > p.liquidationThresholds[IDX_ASSET]) {\\r\\n _borrowToProportions(p, IDX_TOKEN, IDX_ASSET, balanceToken, balanceAsset, true);\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n _borrowToProportions(\\r\\n p,\\r\\n indexCollateral,\\r\\n indexBorrow,\\r\\n IERC20(p.tokens[indexCollateral]).balanceOf(address(this)),\\r\\n IERC20(p.tokens[indexBorrow]).balanceOf(address(this)),\\r\\n checkOppositDebtDoesntExist\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice borrow borrow-asset under collateral-asset, result balances should match to propNotUnderlying18\\r\\n function _borrowToProportions(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow,\\r\\n uint balanceCollateral,\\r\\n uint balanceBorrow,\\r\\n bool checkOppositDebtDoesntExist\\r\\n ) internal {\\r\\n // we are going to change direction of the borrow\\r\\n // let's ensure that there is no debt in opposite direction\\r\\n if (checkOppositDebtDoesntExist) {\\r\\n (uint needToRepay,) = p.converter.getDebtAmountStored(address(this), p.tokens[indexBorrow], p.tokens[indexCollateral], false);\\r\\n require(needToRepay < AppLib.DUST_AMOUNT_TOKENS, AppErrors.OPPOSITE_DEBT_EXISTS);\\r\\n }\\r\\n\\r\\n BorrowLib.RebalanceAssetsCore memory cac = BorrowLib.RebalanceAssetsCore({\\r\\n converterLiquidator: BorrowLib.ConverterLiquidator(p.converter, p.liquidator),\\r\\n assetA: p.tokens[indexCollateral],\\r\\n assetB: p.tokens[indexBorrow],\\r\\n propA: indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18,\\r\\n propB: indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18,\\r\\n // {assetA} to {assetB} ratio; {amountB} * {alpha} => {amountA}, decimals 18\\r\\n alpha18: 1e18 * p.prices[indexBorrow] * p.decs[indexCollateral] / p.prices[indexCollateral] / p.decs[indexBorrow],\\r\\n thresholdA: p.liquidationThresholds[indexCollateral],\\r\\n addonA: 0,\\r\\n addonB: 0,\\r\\n indexA: indexCollateral,\\r\\n indexB: indexBorrow\\r\\n });\\r\\n\\r\\n BorrowLib.openPosition(\\r\\n cac,\\r\\n BorrowLib.PricesDecs({\\r\\n prices: p.prices,\\r\\n decs: p.decs\\r\\n }),\\r\\n balanceCollateral,\\r\\n balanceBorrow\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculate amount that should be repaid to get right proportions of assets on balance\\r\\n /// Analyse only single borrow-direction: indexCollateral => indexBorrow\\r\\n /// @return amountToRepay Amount that should be repaid\\r\\n /// @return borrowInsteadRepay true if repay is not necessary at all and borrow is required instead\\r\\n /// if we need both repay and borrow then false is returned\\r\\n function _getAmountToRepay2(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n uint indexCollateral,\\r\\n uint indexBorrow\\r\\n ) internal view returns (\\r\\n uint amountToRepay,\\r\\n bool borrowInsteadRepay\\r\\n ) {\\r\\n GetAmountToRepay2Local memory v;\\r\\n v.c0 = IERC20(p.tokens[indexCollateral]).balanceOf(address(this)) * p.prices[indexCollateral] / p.decs[indexCollateral];\\r\\n v.b0 = IERC20(p.tokens[indexBorrow]).balanceOf(address(this)) * p.prices[indexBorrow] / p.decs[indexBorrow];\\r\\n\\r\\n v.x = indexCollateral == IDX_ASSET ? 1e18 - p.propNotUnderlying18 : p.propNotUnderlying18;\\r\\n v.y = indexCollateral == IDX_ASSET ? p.propNotUnderlying18 : 1e18 - p.propNotUnderlying18;\\r\\n v.alpha = p.prices[indexCollateral] * p.decs[indexBorrow] * 1e18 / p.prices[indexBorrow] / p.decs[indexCollateral];\\r\\n\\r\\n (uint needToRepay, uint collateralAmountOut) = p.converter.getDebtAmountStored(\\r\\n address(this),\\r\\n p.tokens[indexCollateral],\\r\\n p.tokens[indexBorrow],\\r\\n true\\r\\n );\\r\\n\\r\\n if (needToRepay == 0) {\\r\\n // check if we need to make reverse borrow to fit to proportions: borrow collateral-asset under borrow-asset\\r\\n uint targetCollateral = (v.c0 + v.b0) * v.x / (v.x + v.y);\\r\\n borrowInsteadRepay = targetCollateral > v.c0\\r\\n && targetCollateral - v.c0\\r\\n > (p.liquidationThresholds[indexCollateral] * p.prices[indexCollateral] / p.decs[indexCollateral]);\\r\\n } else {\\r\\n // initial balances: c0, b0\\r\\n // we are going to repay amount b and receive (betta * b, b), where betta ~ alpha * totalCollateral / totalBorrow\\r\\n // we should have x/y = (c0 + betta * b) / (b0 - b)\\r\\n // so b = (x * b0 - y * c0) / (betta * y + x)\\r\\n v.b = (int(v.x * v.b0) - int(v.y * v.c0)) / (int(v.y * v.alpha * collateralAmountOut / needToRepay / 1e18) + int(v.x));\\r\\n if (v.b > 0) {\\r\\n amountToRepay = uint(v.b);\\r\\n }\\r\\n }\\r\\n\\r\\n return (amountToRepay * p.decs[indexBorrow] / p.prices[indexBorrow], borrowInsteadRepay);\\r\\n }\\r\\n\\r\\n /// @notice Swap {aggParams.amountToSwap} using either liquidator or aggregator\\r\\n /// @dev You can use liquidator as aggregator, so aggregator's logic will be used for the liquidator\\r\\n /// @param amountIn Calculated amount to be swapped. It can be different from {aggParams.amountToSwap} a bit,\\r\\n /// but aggregators require exact value {aggParams.amountToSwap}, so amountIn is not used with agg.\\r\\n function _swap(\\r\\n IterationPlanLib.SwapRepayPlanParams memory p,\\r\\n SwapByAggParams memory aggParams,\\r\\n uint indexIn,\\r\\n uint indexOut,\\r\\n uint amountIn\\r\\n ) internal returns (\\r\\n uint spentAmountIn,\\r\\n uint updatedPropNotUnderlying18\\r\\n ) {\\r\\n // liquidator and aggregator have different logic here:\\r\\n // - liquidator uses amountIn to swap\\r\\n // - Aggregator uses amountToSwap for which a route was built off-chain before the call of the swap()\\r\\n // It's allowed to use aggregator == liquidator, so in this way liquidator will use aggregator's logic (for tests)\\r\\n\\r\\n if (!aggParams.useLiquidator) {\\r\\n // aggregator requires exact input amount - aggParams.amountToSwap\\r\\n // actual amount can be a bit different because the quote function was called in different block\\r\\n amountIn = aggParams.amountToSwap;\\r\\n }\\r\\n address aggregator = aggParams.useLiquidator\\r\\n ? address(p.liquidator)\\r\\n : aggParams.aggregator;\\r\\n\\r\\n require(amountIn <= IERC20(p.tokens[indexIn]).balanceOf(address(this)), AppErrors.NOT_ENOUGH_BALANCE);\\r\\n // let's ensure that \\\"next swap\\\" is made using correct token\\r\\n require(aggParams.tokenToSwap == p.tokens[indexIn], AppErrors.INCORRECT_SWAP_BY_AGG_PARAM);\\r\\n\\r\\n if (amountIn > p.liquidationThresholds[indexIn]) {\\r\\n // infinite approve for aggregator is unsafe\\r\\n AppLib.approveForced(p.tokens[indexIn], amountIn, aggregator);\\r\\n\\r\\n uint balanceTokenOutBefore = AppLib.balance(p.tokens[indexOut]);\\r\\n\\r\\n if (aggParams.useLiquidator) {\\r\\n amountIn = Math.min(amountIn, aggParams.amountToSwap);\\r\\n (spentAmountIn,) = ConverterStrategyBaseLib._liquidate(\\r\\n p.converter,\\r\\n ITetuLiquidator(aggregator),\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut],\\r\\n amountIn,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE,\\r\\n p.liquidationThresholds[indexIn],\\r\\n true\\r\\n );\\r\\n } else {\\r\\n if (aggregator != address(p.liquidator)) {\\r\\n _checkSwapRouter(aggregator);\\r\\n }\\r\\n\\r\\n (bool success, bytes memory result) = aggregator.call(aggParams.swapData);\\r\\n require(success, string(result));\\r\\n\\r\\n spentAmountIn = amountIn;\\r\\n }\\r\\n\\r\\n require(\\r\\n p.converter.isConversionValid(\\r\\n p.tokens[indexIn],\\r\\n amountIn,\\r\\n p.tokens[indexOut],\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n _ASSET_LIQUIDATION_SLIPPAGE\\r\\n ), AppErrors.PRICE_IMPACT);\\r\\n\\r\\n emit SwapByAgg(\\r\\n aggParams.amountToSwap,\\r\\n amountIn,\\r\\n AppLib.balance(p.tokens[indexOut]) - balanceTokenOutBefore,\\r\\n amountIn * p.prices[indexIn] * p.decs[indexOut] / p.prices[indexOut] / p.decs[indexIn],\\r\\n aggregator,\\r\\n p.tokens[indexIn],\\r\\n p.tokens[indexOut]\\r\\n );\\r\\n }\\r\\n\\r\\n return (\\r\\n spentAmountIn,\\r\\n // p.propNotUnderlying18 contains original proportions that were valid before the swap\\r\\n // after swap() we need to re-read new values from the pool\\r\\n p.usePoolProportions\\r\\n ? IPoolProportionsProvider(address(this)).getPropNotUnderlying18()\\r\\n : p.propNotUnderlying18\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------ Internal helper functions\\r\\n\\r\\n //region ----------------------------------------- Utils\\r\\n function getPoolPriceAdjustment(uint poolPriceDecimals) external pure returns (uint adjustment) {\\r\\n // we assume that decimals never higher than 18\\r\\n adjustment = poolPriceDecimals < 18 ? 10 ** (18 - poolPriceDecimals) : 1;\\r\\n }\\r\\n\\r\\n function _checkSwapRouter(address router) internal pure {\\r\\n require(router == ONEINCH || router == OPENOCEAN || router == OPENOCEAN_ZKEVM, UNKNOWN_SWAP_ROUTER);\\r\\n }\\r\\n\\r\\n /// @notice Extract propNotUnderlying18 from {planEntryData} of the given {planKind}\\r\\n function _extractProp(uint planKind, bytes memory planEntryData) internal pure returns (\\r\\n uint propNotUnderlying18,\\r\\n uint entryDataParamValue\\r\\n ) {\\r\\n if (planKind == IterationPlanLib.PLAN_SWAP_REPAY || planKind == IterationPlanLib.PLAN_SWAP_ONLY) {\\r\\n (, propNotUnderlying18) = abi.decode(planEntryData, (uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n } else {\\r\\n require(planKind == IterationPlanLib.PLAN_REPAY_SWAP_REPAY, AppErrors.WRONG_VALUE);\\r\\n // save \\\"required-amount-to-reduce-debt\\\" to entryDataParamValue\\r\\n (, propNotUnderlying18, entryDataParamValue) = abi.decode(planEntryData, (uint, uint, uint));\\r\\n require(propNotUnderlying18 <= 1e18 || propNotUnderlying18 == type(uint).max, AppErrors.INVALID_VALUE); // 0 is allowed\\r\\n }\\r\\n return (propNotUnderlying18, entryDataParamValue);\\r\\n }\\r\\n //endregion ------------------------------------------ Utils\\r\\n}\\r\\n\",\"keccak256\":\"0x33ba728785e3e0fe41ae312fb091a518303b27a81c76f88edd3f3b0c28b4849b\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/pair/PairBasedStrategyLogicLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"@tetu_io/tetu-converter/contracts/interfaces/ITetuConverter.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib.sol\\\";\\r\\nimport \\\"./PairBasedStrategyLib.sol\\\";\\r\\nimport \\\"../ConverterStrategyBaseLib2.sol\\\";\\r\\n\\r\\n/// @notice Library for the UniV3-like strategies with two tokens in the pool\\r\\nlibrary PairBasedStrategyLogicLib {\\r\\n //region ------------------------------------------------------- Data types\\r\\n /// @notice Local variables required inside withdrawByAggStep and quoteWithdrawByAgg\\r\\n struct WithdrawLocal {\\r\\n /// @notice [underlying, not-underlying]\\r\\n address[] tokens;\\r\\n address controller;\\r\\n /// @notice liquidationThresholds for the {tokens}, greater or equal to {DEFAULT_LIQUIDATION_THRESHOLD}\\r\\n uint[] liquidationThresholds;\\r\\n uint planKind;\\r\\n uint propNotUnderlying18;\\r\\n uint entryDataParam;\\r\\n }\\r\\n\\r\\n /// @notice Common part of all XXXXConverterStrategyLogicLib.State\\r\\n struct PairState {\\r\\n address pool;\\r\\n address strategyProfitHolder;\\r\\n /// @notice This is underlying\\r\\n address tokenA;\\r\\n /// @notice This is not underlying\\r\\n address tokenB;\\r\\n\\r\\n bool isStablePool;\\r\\n /// @notice Tokens are swapped in the pool (pool.tokenB is underlying, pool.tokenA is not-underlying)\\r\\n bool depositorSwapTokens;\\r\\n\\r\\n int24 tickSpacing;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n int24 rebalanceTickRange;\\r\\n uint128 totalLiquidity;\\r\\n\\r\\n /// @notice Fuse for tokens\\r\\n PairBasedStrategyLib.FuseStateParams fuseAB;\\r\\n\\r\\n /// @notice 1 means that the fuse was triggered ON and then all debts were closed\\r\\n /// and assets were converter to underlying using withdrawStepByAgg.\\r\\n /// This flag is automatically cleared to 0 if fuse is triggered OFF.\\r\\n uint withdrawDone;\\r\\n\\r\\n /// @notice Timestamp of last call of rebalanceNoSwaps() or zero if withdrawByAggStep() was called last\\r\\n uint lastRebalanceNoSwap;\\r\\n\\r\\n /// @notice reserve space for future needs\\r\\n uint[50 - 17] __gap;\\r\\n }\\r\\n\\r\\n struct RebalanceNoSwapsLocal {\\r\\n address tokenA;\\r\\n address tokenB;\\r\\n bool depositorSwapTokens;\\r\\n int24 newLowerTick;\\r\\n int24 newUpperTick;\\r\\n uint prop0;\\r\\n uint prop1;\\r\\n }\\r\\n\\r\\n struct WithdrawByAggStepLocal {\\r\\n PairBasedStrategyLogicLib.WithdrawLocal w;\\r\\n address tokenToSwap;\\r\\n address aggregator;\\r\\n address controller;\\r\\n address converter;\\r\\n address splitter;\\r\\n uint amountToSwap;\\r\\n uint profitToCover;\\r\\n uint oldTotalAssets;\\r\\n uint entryToPool;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Data types\\r\\n\\r\\n //region ------------------------------------------------------- Events\\r\\n //endregion ------------------------------------------------------- Events\\r\\n\\r\\n //region ------------------------------------------------------- Helpers\\r\\n /// @notice Prepare array of amounts ready to deposit, borrow missed amounts\\r\\n /// @param amount_ Amount of tokenA\\r\\n /// @param tokenA Underlying\\r\\n /// @param tokenB Not-underlying\\r\\n /// @param prop0 Required proportion of underlying, > 0. Proportion of not-underlying is calculates as 1e18 - {prop0}\\r\\n /// @param liquidationThresholds Dust-thresholds for the tokens A and B\\r\\n /// @return tokenAmounts Amounts of token A and B to be deposited, [A, B]\\r\\n function _beforeDeposit(\\r\\n ITetuConverter tetuConverter_,\\r\\n uint amount_,\\r\\n address tokenA,\\r\\n address tokenB,\\r\\n uint prop0,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n uint[] memory tokenAmounts\\r\\n ) {\\r\\n return BorrowLib.prepareToDeposit(\\r\\n tetuConverter_,\\r\\n amount_,\\r\\n [tokenA, tokenB],\\r\\n [\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenA]),\\r\\n AppLib._getLiquidationThreshold(liquidationThresholds[tokenB])\\r\\n ],\\r\\n prop0\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Initialize {dest} in place. Underlying is always first in {dest.tokens}.\\r\\n /// @param tokens_ [underlying, not-underlying]\\r\\n function initWithdrawLocal(\\r\\n WithdrawLocal memory dest,\\r\\n address[2] memory tokens_,\\r\\n mapping(address => uint) storage liquidationThresholds,\\r\\n bytes memory planEntryData,\\r\\n address controller\\r\\n ) internal view { // it's internal because it initializes {dest}\\r\\n dest.controller = controller;\\r\\n StrategyLib2.onlyOperators(dest.controller);\\r\\n\\r\\n dest.planKind = IterationPlanLib.getEntryKind(planEntryData);\\r\\n (dest.propNotUnderlying18, dest.entryDataParam) = PairBasedStrategyLib._extractProp(dest.planKind, planEntryData);\\r\\n\\r\\n dest.tokens = new address[](2);\\r\\n (dest.tokens[0], dest.tokens[1]) = (tokens_[0], tokens_[1]);\\r\\n\\r\\n dest.liquidationThresholds = new uint[](2);\\r\\n dest.liquidationThresholds[0] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[0]]);\\r\\n dest.liquidationThresholds[1] = AppLib._getLiquidationThreshold(liquidationThresholds[dest.tokens[1]]);\\r\\n }\\r\\n\\r\\n function calcTickRange(int24 tick, int24 tickRange, int24 tickSpacing) public pure returns (\\r\\n int24 lowerTick,\\r\\n int24 upperTick\\r\\n ) {\\r\\n if (tick < 0 && tick / tickSpacing * tickSpacing != tick) {\\r\\n lowerTick = ((tick - tickRange) / tickSpacing - 1) * tickSpacing;\\r\\n } else {\\r\\n lowerTick = (tick - tickRange) / tickSpacing * tickSpacing;\\r\\n }\\r\\n upperTick = tickRange == 0 ? lowerTick + tickSpacing : lowerTick + tickRange * 2;\\r\\n }\\r\\n //endregion ------------------------------------------------------- Helpers\\r\\n\\r\\n //region ------------------------------------------------------- PairState-helpers\\r\\n /// @notice Set the initial values to PairState instance\\r\\n /// @param pairState Depositor storage state struct to be initialized\\r\\n /// @param addr [pool, asset, pool.token0(), pool.token1()]\\r\\n /// asset: Underlying asset of the depositor.\\r\\n /// @param tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @param fuseThresholds Fuse thresholds for tokens (stable pool only)\\r\\n function setInitialDepositorValues(\\r\\n PairState storage pairState,\\r\\n address[4] calldata addr,\\r\\n int24[4] calldata tickData,\\r\\n bool isStablePool_,\\r\\n uint[4] calldata fuseThresholds\\r\\n ) external {\\r\\n pairState.pool = addr[0];\\r\\n address asset = addr[1];\\r\\n address token0 = addr[2];\\r\\n address token1 = addr[3];\\r\\n\\r\\n pairState.tickSpacing = tickData[0];\\r\\n pairState.lowerTick = tickData[1];\\r\\n pairState.upperTick = tickData[2];\\r\\n pairState.rebalanceTickRange = tickData[3];\\r\\n\\r\\n require(asset == token0 || asset == token1, PairBasedStrategyLib.INCORRECT_ASSET);\\r\\n if (asset == token0) {\\r\\n pairState.tokenA = token0;\\r\\n pairState.tokenB = token1;\\r\\n pairState.depositorSwapTokens = false;\\r\\n } else {\\r\\n pairState.tokenA = token1;\\r\\n pairState.tokenB = token0;\\r\\n pairState.depositorSwapTokens = true;\\r\\n }\\r\\n\\r\\n if (isStablePool_) {\\r\\n /// for stable pools fuse can be enabled\\r\\n pairState.isStablePool = true;\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, PairBasedStrategyLib.FuseStatus.FUSE_OFF_1);\\r\\n PairBasedStrategyLib.setFuseThresholds(pairState.fuseAB, fuseThresholds);\\r\\n }\\r\\n\\r\\n // totalLiquidity is 0, no need to initialize\\r\\n // withdrawDone is 0, no need to initialize\\r\\n }\\r\\n\\r\\n function updateFuseStatus(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) external {\\r\\n bool updated;\\r\\n if (fuseStatusChangedAB) {\\r\\n PairBasedStrategyLib.setFuseStatus(pairState.fuseAB, fuseStatusAB);\\r\\n updated = true;\\r\\n }\\r\\n\\r\\n if (updated) {\\r\\n // if fuse is triggered ON, full-withdraw is required\\r\\n // if fuse is triggered OFF, the assets will be deposited back to pool\\r\\n // in both cases withdrawDone should be reset\\r\\n pairState.withdrawDone = 0;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Returns the current state of the contract\\r\\n /// @return addr [tokenA, tokenB, pool, profitHolder]\\r\\n /// @return tickData [tickSpacing, lowerTick, upperTick, rebalanceTickRange]\\r\\n /// @return nums [totalLiquidity, fuse-status-tokenA, withdrawDone, 4 thresholds of token A, lastRebalanceNoSwap, 5 reserved values]\\r\\n /// @return boolValues [isStablePool, depositorSwapTokens]\\r\\n function getDefaultState(PairBasedStrategyLogicLib.PairState storage pairState) external view returns (\\r\\n address[] memory addr,\\r\\n int24[] memory tickData,\\r\\n uint[] memory nums,\\r\\n bool[] memory boolValues\\r\\n ) {\\r\\n addr = new address[](4);\\r\\n tickData = new int24[](4);\\r\\n nums = new uint[](13);\\r\\n boolValues = new bool[](2);\\r\\n\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_A] = pairState.tokenA;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_TOKEN_B] = pairState.tokenB;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_POOL] = pairState.pool;\\r\\n addr[PairBasedStrategyLib.IDX_ADDR_DEFAULT_STATE_PROFIT_HOLDER] = pairState.strategyProfitHolder;\\r\\n\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_TICK_SPACING] = pairState.tickSpacing;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_LOWER_TICK] = pairState.lowerTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_UPPER_TICK] = pairState.upperTick;\\r\\n tickData[PairBasedStrategyLib.IDX_TICK_DEFAULT_STATE_REBALANCE_TICK_RANGE] = pairState.rebalanceTickRange;\\r\\n\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_TOTAL_LIQUIDITY] = uint(pairState.totalLiquidity);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_FUSE_STATUS] = uint(pairState.fuseAB.status);\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_WITHDRAW_DONE] = pairState.withdrawDone;\\r\\n for (uint i = 0; i < 4; ++i) {\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_THRESHOLD_0 + i] = pairState.fuseAB.thresholds[i];\\r\\n }\\r\\n nums[PairBasedStrategyLib.IDX_NUMS_DEFAULT_STATE_LAST_REBALANCE_NO_SWAP] = pairState.lastRebalanceNoSwap;\\r\\n\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_IS_STABLE_POOL] = pairState.isStablePool;\\r\\n boolValues[PairBasedStrategyLib.IDX_BOOL_VALUES_DEFAULT_STATE_DEPOSITOR_SWAP_TOKENS] = pairState.depositorSwapTokens;\\r\\n }\\r\\n\\r\\n /// @notice Get info about a swap required by next call of {withdrawByAggStep} within the given plan\\r\\n /// @param amounts_ Amounts of [underlying, not-underlying] that will be received from the pool before withdrawing\\r\\n function quoteWithdrawByAgg(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n bytes memory planEntryData,\\r\\n uint[] memory amounts_,\\r\\n address controller_,\\r\\n ITetuConverter converter_,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n address tokenToSwap,\\r\\n uint amountToSwap\\r\\n ) {\\r\\n // check operator-only, initialize w\\r\\n WithdrawLocal memory w;\\r\\n initWithdrawLocal(\\r\\n w,\\r\\n [pairState.tokenA, pairState.tokenB],\\r\\n liquidationThresholds,\\r\\n planEntryData,\\r\\n controller_\\r\\n );\\r\\n\\r\\n (tokenToSwap, amountToSwap) = PairBasedStrategyLib.quoteWithdrawStep(\\r\\n [address(converter_), address(AppLib._getLiquidator(w.controller))],\\r\\n w.tokens,\\r\\n w.liquidationThresholds,\\r\\n amounts_,\\r\\n w.planKind,\\r\\n [w.propNotUnderlying18, w.entryDataParam]\\r\\n );\\r\\n\\r\\n if (amountToSwap != 0) {\\r\\n // withdrawByAggStep will execute REPAY1 - SWAP - REPAY2\\r\\n // but quoteWithdrawByAgg and withdrawByAggStep are executed in different blocks\\r\\n // so, REPAY1 can return less collateral than quoteWithdrawByAgg expected\\r\\n // As result, we can have less amount on balance than required amountToSwap\\r\\n // So, we need to reduce amountToSwap on small gap amount\\r\\n amountToSwap -= amountToSwap * PairBasedStrategyLib.GAP_AMOUNT_TO_SWAP / 100_000;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculate amounts to be deposited to pool, calculate loss, fix profitToCover\\r\\n /// @param addr_ [tokenToSwap, aggregator, controller, converter, splitter]\\r\\n /// @param values_ [amountToSwap_, profitToCover, oldTotalAssets, not used here]\\r\\n /// @param tokens [underlying, not-underlying] (values been read from pairBase)\\r\\n /// @return completed All debts were closed, leftovers were swapped to proper proportions\\r\\n /// @return tokenAmounts Amounts to be deposited to pool. If {tokenAmounts} contains zero amount return empty array.\\r\\n function withdrawByAggStep(\\r\\n address[5] calldata addr_,\\r\\n uint[4] calldata values_,\\r\\n bytes memory swapData,\\r\\n bytes memory planEntryData,\\r\\n address[2] memory tokens,\\r\\n mapping(address => uint) storage liquidationThresholds\\r\\n ) external returns (\\r\\n bool completed,\\r\\n uint[] memory tokenAmounts,\\r\\n uint loss\\r\\n ) {\\r\\n WithdrawByAggStepLocal memory v;\\r\\n\\r\\n v.tokenToSwap = addr_[0];\\r\\n v.aggregator = addr_[1];\\r\\n v.controller = addr_[2];\\r\\n v.converter = addr_[3];\\r\\n v.splitter = addr_[4];\\r\\n\\r\\n v.amountToSwap = values_[0];\\r\\n v.profitToCover = values_[1];\\r\\n v.oldTotalAssets = values_[2];\\r\\n\\r\\n // initialize v\\r\\n PairBasedStrategyLogicLib.initWithdrawLocal(v.w, tokens, liquidationThresholds, planEntryData, v.controller);\\r\\n\\r\\n // make withdraw iteration according to the selected plan\\r\\n completed = PairBasedStrategyLib.withdrawStep(\\r\\n [v.converter, address(AppLib._getLiquidator(v.w.controller))],\\r\\n v.w.tokens,\\r\\n v.w.liquidationThresholds,\\r\\n v.tokenToSwap,\\r\\n v.amountToSwap,\\r\\n v.aggregator,\\r\\n swapData,\\r\\n v.aggregator == address(0),\\r\\n v.w.planKind,\\r\\n [v.w.propNotUnderlying18, v.w.entryDataParam]\\r\\n );\\r\\n\\r\\n // fix loss / profitToCover\\r\\n if (v.profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(\\r\\n v.w.tokens[0],\\r\\n v.profitToCover,\\r\\n v.splitter,\\r\\n v.oldTotalAssets,\\r\\n IERC20(v.w.tokens[0]).balanceOf(address(this))\\r\\n );\\r\\n }\\r\\n\\r\\n (loss, tokenAmounts) = ConverterStrategyBaseLib2.getTokenAmountsPair(\\r\\n ITetuConverter(v.converter),\\r\\n v.oldTotalAssets,\\r\\n v.w.tokens[0],\\r\\n v.w.tokens[1],\\r\\n [v.w.liquidationThresholds[0], v.w.liquidationThresholds[1]]\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Rebalance asset to proportions {propTokenA}:{1e18-propTokenA}, fix profitToCover\\r\\n /// @param propTokenA Proportion of {tokenA}, > 0. Proportion of {tokenB} is calculates as 1e18 - prop0\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function _rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n uint propTokenA\\r\\n ) internal {\\r\\n address tokenA = pairState.tokenA;\\r\\n address tokenB = pairState.tokenB;\\r\\n\\r\\n BorrowLib.rebalanceAssets(\\r\\n ITetuConverter(converterLiquidator[0]),\\r\\n ITetuLiquidator(converterLiquidator[1]),\\r\\n tokenA,\\r\\n tokenB,\\r\\n propTokenA,\\r\\n liquidationThresholdsAB[0], // liquidityThreshold of token A\\r\\n liquidationThresholdsAB[1], // liquidityThreshold of token B\\r\\n profitToCover\\r\\n );\\r\\n\\r\\n // we assume here, that rebalanceAssets provides profitToCover on balance and set leftovers to right proportions\\r\\n if (profitToCover != 0) {\\r\\n ConverterStrategyBaseLib2.sendToInsurance(tokenA, profitToCover, splitter, totalAssets, IERC20(tokenA).balanceOf(address(this)));\\r\\n }\\r\\n }\\r\\n //endregion ------------------------------------------------------- PairState-helpers\\r\\n\\r\\n //region ------------------------------------------------------- needStrategyRebalance\\r\\n /// @notice Determine if the strategy needs to be rebalanced.\\r\\n /// @return needRebalance A boolean indicating if {rebalanceNoSwaps} should be called\\r\\n function needStrategyRebalance(\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n ITetuConverter converter_,\\r\\n int24 tick,\\r\\n uint poolPrice\\r\\n ) external view returns (\\r\\n bool needRebalance,\\r\\n bool fuseStatusChangedAB,\\r\\n PairBasedStrategyLib.FuseStatus fuseStatusAB\\r\\n ) {\\r\\n if (pairState.isStablePool) {\\r\\n uint price = ConverterStrategyBaseLib2.getOracleAssetsPrice(\\r\\n converter_,\\r\\n pairState.tokenA,\\r\\n pairState.tokenB\\r\\n );\\r\\n (fuseStatusChangedAB, fuseStatusAB) = PairBasedStrategyLib.needChangeFuseStatus(pairState.fuseAB, price, poolPrice);\\r\\n needRebalance = fuseStatusChangedAB\\r\\n || (\\r\\n !PairBasedStrategyLib.isFuseTriggeredOn(fuseStatusAB)\\r\\n && _needPoolRebalance(pairState, tick)\\r\\n );\\r\\n } else {\\r\\n needRebalance = _needPoolRebalance(pairState, tick);\\r\\n }\\r\\n\\r\\n return (needRebalance, fuseStatusChangedAB, fuseStatusAB); // hide warning\\r\\n }\\r\\n\\r\\n /// @notice Determine if the pool needs to be rebalanced.\\r\\n /// @return A boolean indicating if the pool needs to be rebalanced.\\r\\n function _needPoolRebalance(\\r\\n int24 tick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing,\\r\\n int24 rebalanceTickRange\\r\\n ) internal pure returns (bool) {\\r\\n if (upperTick - lowerTick == tickSpacing) {\\r\\n return tick < lowerTick || tick >= upperTick;\\r\\n } else {\\r\\n int24 halfRange = (upperTick - lowerTick) / 2;\\r\\n int24 oldMedianTick = lowerTick + halfRange;\\r\\n return (tick > oldMedianTick)\\r\\n ? tick - oldMedianTick >= rebalanceTickRange\\r\\n : oldMedianTick - tick > rebalanceTickRange;\\r\\n }\\r\\n }\\r\\n\\r\\n function _needPoolRebalance(PairBasedStrategyLogicLib.PairState storage pairState, int24 tick) internal view returns (bool) {\\r\\n return _needPoolRebalance(\\r\\n tick,\\r\\n pairState.lowerTick,\\r\\n pairState.upperTick,\\r\\n pairState.tickSpacing,\\r\\n pairState.rebalanceTickRange\\r\\n );\\r\\n }\\r\\n //endregion ------------------------------------------------------- needStrategyRebalance\\r\\n}\\r\\n\",\"keccak256\":\"0xa1de412c47d5ef698afdb1fe0afe130a9b66dae28ef90aaec4349ca482f24863\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/Uni3StrategyErrors.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nlibrary Uni3StrategyErrors {\\r\\n\\r\\n string public constant NEED_REBALANCE = \\\"U3S-1 Need rebalance\\\";\\r\\n string public constant WRONG_BALANCE = \\\"U3S-2 Wrong balance\\\";\\r\\n string public constant INCORRECT_TICK_RANGE = \\\"U3S-3 Incorrect tickRange\\\";\\r\\n string public constant INCORRECT_REBALANCE_TICK_RANGE = \\\"U3S-4 Incorrect rebalanceTickRange\\\";\\r\\n string public constant INCORRECT_ASSET = \\\"U3S-5 Incorrect asset\\\";\\r\\n string public constant WRONG_FEE = \\\"U3S-6 Wrong fee\\\";\\r\\n string public constant WRONG_LIQUIDITY = \\\"U3S-7 Wrong liquidity\\\";\\r\\n string public constant WRONG_FILLUP = \\\"U3S-8 Wrong fillup\\\";\\r\\n string public constant NO_REBALANCE_NEEDED = \\\"U3S-9 No rebalance needed\\\";\\r\\n string public constant BALANCE_LOWER_THAN_FEE = \\\"U3S-10 Balance lower than fee\\\";\\r\\n string public constant NOT_CALLBACK_CALLER = \\\"U3S-11 Not callback caller\\\";\\r\\n string public constant ZERO_PROFIT_HOLDER = \\\"U3S-13 Zero strategy profit holder\\\";\\r\\n string public constant FUSE_IS_ACTIVE = \\\"U3S-14 Fuse is active\\\";\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x4c4e17e0aae23d4739157d7eccd78ac18ae33e20db4696f32c59e429786f7bb0\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3DebtLib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"./UniswapV3Lib.sol\\\";\\r\\nimport \\\"./Uni3StrategyErrors.sol\\\";\\r\\nimport \\\"../../libs/BorrowLib.sol\\\";\\r\\nimport \\\"../pair/PairBasedStrategyLogicLib.sol\\\";\\r\\n\\r\\nlibrary UniswapV3DebtLib {\\r\\n using SafeERC20 for IERC20;\\r\\n\\r\\n//region -------------------------------------------- Constants\\r\\n uint public constant SELL_GAP = 100;\\r\\n /// @dev should be placed local, probably will be adjusted later\\r\\n uint internal constant BORROW_PERIOD_ESTIMATION = 30 days / 2;\\r\\n//endregion -------------------------------------------- Constants\\r\\n\\r\\n//region -------------------------------------------- Entry data\\r\\n /// @notice Calculate proportions of the tokens for entry kind 1\\r\\n /// @param pool Pool instance\\r\\n /// @param lowerTick The lower tick of the pool's main range.\\r\\n /// @param upperTick The upper tick of the pool's main range.\\r\\n /// @param depositorSwapTokens A boolean indicating if need to use token B instead of token A.\\r\\n /// @return prop0 Proportion onf token A. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n /// @return prop1 Proportion onf token B. Any decimals are allowed, prop[0 or 1]/(prop0 + prop1) are important only\\r\\n function getEntryDataProportions(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n bool depositorSwapTokens\\r\\n ) internal view returns (uint, uint) {\\r\\n address token1 = pool.token1();\\r\\n uint token1Price = UniswapV3Lib.getPrice(address(pool), token1);\\r\\n\\r\\n uint token1Decimals = IERC20Metadata(token1).decimals();\\r\\n\\r\\n uint token0Desired = token1Price;\\r\\n uint token1Desired = 10 ** token1Decimals;\\r\\n require(token1Desired != 0, AppErrors.ZERO_VALUE);\\r\\n\\r\\n // calculate proportions\\r\\n (uint consumed0, uint consumed1,) = UniswapV3Lib.addLiquidityPreview(address(pool), lowerTick, upperTick, token0Desired, token1Desired);\\r\\n\\r\\n return depositorSwapTokens\\r\\n ? (1e18*consumed1 * token1Price / token1Desired, 1e18*consumed0)\\r\\n : (1e18*consumed0, 1e18*consumed1 * token1Price / token1Desired);\\r\\n }\\r\\n//endregion -------------------------------------------- Entry data\\r\\n\\r\\n//region -------------------------------------------- Calc tick range\\r\\n function calcTickRange(address pool, int24 tickRange, int24 tickSpacing) public view returns (int24 lowerTick, int24 upperTick) {\\r\\n return PairBasedStrategyLogicLib.calcTickRange(getCurrentTick(IUniswapV3Pool(pool)), tickRange, tickSpacing);\\r\\n }\\r\\n\\r\\n function getCurrentTick(IUniswapV3Pool pool) public view returns(int24 tick) {\\r\\n (, tick, , , , ,) = IUniswapV3Pool(pool).slot0();\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is read from the pool.\\r\\n /// @param pool The Uniswap V3 pool to calculate the new tick range for.\\r\\n /// @param lowerTick The current lower tick value for the pool.\\r\\n /// @param upperTick The current upper tick value for the pool.\\r\\n /// @param tickSpacing The tick spacing for the pool.\\r\\n /// @return lowerTickNew The new lower tick value for the pool.\\r\\n /// @return upperTickNew The new upper tick value for the pool.\\r\\n function _calcNewTickRange(\\r\\n IUniswapV3Pool pool,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal view returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 currentTick = getCurrentTick(pool);\\r\\n return _calcNewTickRangeForTick(currentTick, lowerTick, upperTick, tickSpacing);\\r\\n }\\r\\n\\r\\n /// @notice Calculate the new tick range for a Uniswap V3 pool, the tick is known\\r\\n function _calcNewTickRangeForTick(\\r\\n int24 currentTick,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n int24 tickSpacing\\r\\n ) internal pure returns (int24 lowerTickNew, int24 upperTickNew) {\\r\\n int24 fullTickRange = upperTick - lowerTick;\\r\\n int24 tickRange = fullTickRange == tickSpacing\\r\\n ? int24(0)\\r\\n : fullTickRange / 2;\\r\\n return PairBasedStrategyLogicLib.calcTickRange(currentTick, tickRange, tickSpacing);\\r\\n }\\r\\n//endregion -------------------------------------------- Calc tick range\\r\\n\\r\\n//region -------------------------------------------- Rebalance\\r\\n /// @notice Calculate right asset proportions, make rebalance, update lower/upper ticks in {pairState}\\r\\n /// @param tick Current tick in the pool\\r\\n /// @param liquidationThresholdsAB [liquidityThreshold of token A, liquidityThreshold of tokenB]\\r\\n function rebalanceNoSwaps(\\r\\n address[2] calldata converterLiquidator,\\r\\n PairBasedStrategyLogicLib.PairState storage pairState,\\r\\n uint profitToCover,\\r\\n uint totalAssets,\\r\\n address splitter,\\r\\n uint[2] calldata liquidationThresholdsAB,\\r\\n int24 tick\\r\\n ) external {\\r\\n (int24 newLowerTick, int24 newUpperTick) = _calcNewTickRangeForTick(tick, pairState.lowerTick, pairState.upperTick, pairState.tickSpacing);\\r\\n (uint prop0, uint prop1) = getEntryDataProportions(IUniswapV3Pool(pairState.pool), newLowerTick, newUpperTick, pairState.depositorSwapTokens);\\r\\n PairBasedStrategyLogicLib._rebalanceNoSwaps(\\r\\n converterLiquidator,\\r\\n pairState,\\r\\n profitToCover,\\r\\n totalAssets,\\r\\n splitter,\\r\\n liquidationThresholdsAB,\\r\\n prop0 * BorrowLib.SUM_PROPORTIONS / (prop0 + prop1)\\r\\n );\\r\\n (pairState.lowerTick, pairState.upperTick) = (newLowerTick, newUpperTick);\\r\\n }\\r\\n//endregion -------------------------------------------- Rebalance\\r\\n\\r\\n}\\r\\n\",\"keccak256\":\"0x1786c601c9e0f169f22b940becc164d65f3917b3954011ee961398ad98652d43\",\"license\":\"BUSL-1.1\"},\"contracts/strategies/uniswap/UniswapV3Lib.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\r\\npragma solidity 0.8.17;\\r\\n\\r\\nimport \\\"../../integrations/uniswap/IUniswapV3Pool.sol\\\";\\r\\nimport \\\"@tetu_io/tetu-contracts-v2/contracts/interfaces/IERC20Metadata.sol\\\";\\r\\n\\r\\n/// @title Uniswap V3 liquidity management helper\\r\\n/// @notice Provides functions for computing liquidity amounts from token amounts and prices\\r\\nlibrary UniswapV3Lib {\\r\\n uint8 internal constant RESOLUTION = 96;\\r\\n uint internal constant Q96 = 0x1000000000000000000000000;\\r\\n uint private constant TWO_96 = 2 ** 96;\\r\\n /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\\r\\n uint160 private constant MIN_SQRT_RATIO = 4295128739 + 1;\\r\\n /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\\r\\n uint160 private constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342 - 1;\\r\\n /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\\r\\n int24 internal constant MIN_TICK = - 887272;\\r\\n /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\\r\\n int24 internal constant MAX_TICK = - MIN_TICK;\\r\\n\\r\\n struct PoolPosition {\\r\\n address pool;\\r\\n int24 lowerTick;\\r\\n int24 upperTick;\\r\\n uint128 liquidity;\\r\\n address owner;\\r\\n }\\r\\n\\r\\n function getTickSpacing(uint24 fee) external pure returns (int24) {\\r\\n if (fee == 10000) {\\r\\n return 200;\\r\\n }\\r\\n if (fee == 3000) {\\r\\n return 60;\\r\\n }\\r\\n if (fee == 500) {\\r\\n return 10;\\r\\n }\\r\\n return 1;\\r\\n }\\r\\n\\r\\n function getFees(PoolPosition memory position) public view returns (uint fee0, uint fee1) {\\r\\n bytes32 positionId = _getPositionId(position);\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n (, int24 tick, , , , ,) = pool.slot0();\\r\\n (, uint feeGrowthInside0Last, uint feeGrowthInside1Last, uint128 tokensOwed0, uint128 tokensOwed1) = pool.positions(positionId);\\r\\n fee0 = _computeFeesEarned(position, true, feeGrowthInside0Last, tick) + uint(tokensOwed0);\\r\\n fee1 = _computeFeesEarned(position, false, feeGrowthInside1Last, tick) + uint(tokensOwed1);\\r\\n }\\r\\n\\r\\n function addLiquidityPreview(address pool_, int24 lowerTick_, int24 upperTick_, uint amount0Desired_, uint amount1Desired_) external view returns (uint amount0Consumed, uint amount1Consumed, uint128 liquidityOut) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n (uint160 sqrtRatioX96, , , , , ,) = pool.slot0();\\r\\n liquidityOut = getLiquidityForAmounts(sqrtRatioX96, lowerTick_, upperTick_, amount0Desired_, amount1Desired_);\\r\\n (amount0Consumed, amount1Consumed) = getAmountsForLiquidity(sqrtRatioX96, lowerTick_, upperTick_, liquidityOut);\\r\\n }\\r\\n\\r\\n /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getLiquidityForAmounts(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint amount0,\\r\\n uint amount1\\r\\n ) public pure returns (uint128 liquidity) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n liquidity = _getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n uint128 liquidity0 = _getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);\\r\\n uint128 liquidity1 = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);\\r\\n liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;\\r\\n } else {\\r\\n liquidity = _getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current\\r\\n /// pool prices and the prices at the tick boundaries\\r\\n function getAmountsForLiquidity(\\r\\n uint160 sqrtRatioX96,\\r\\n int24 lowerTick,\\r\\n int24 upperTick,\\r\\n uint128 liquidity\\r\\n ) public pure returns (uint amount0, uint amount1) {\\r\\n uint160 sqrtRatioAX96 = _getSqrtRatioAtTick(lowerTick);\\r\\n uint160 sqrtRatioBX96 = _getSqrtRatioAtTick(upperTick);\\r\\n\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n if (sqrtRatioX96 <= sqrtRatioAX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n } else if (sqrtRatioX96 < sqrtRatioBX96) {\\r\\n amount0 = _getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);\\r\\n } else {\\r\\n amount1 = _getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates floor(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\\r\\n function mulDiv(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) public pure returns (uint result) {\\r\\n unchecked {\\r\\n // 512-bit multiply [prod1 prod0] = a * b\\r\\n // Compute the product mod 2**256 and mod 2**256 - 1\\r\\n // then use the Chinese Remainder Theorem to reconstruct\\r\\n // the 512 bit result. The result is stored in two 256\\r\\n // variables such that product = prod1 * 2**256 + prod0\\r\\n uint prod0;\\r\\n // Least significant 256 bits of the product\\r\\n uint prod1;\\r\\n // Most significant 256 bits of the product\\r\\n assembly {\\r\\n let mm := mulmod(a, b, not(0))\\r\\n prod0 := mul(a, b)\\r\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\r\\n }\\r\\n\\r\\n // Handle non-overflow cases, 256 by 256 division\\r\\n if (prod1 == 0) {\\r\\n require(denominator > 0);\\r\\n assembly {\\r\\n result := div(prod0, denominator)\\r\\n }\\r\\n return result;\\r\\n }\\r\\n\\r\\n // Make sure the result is less than 2**256.\\r\\n // Also prevents denominator == 0\\r\\n require(denominator > prod1);\\r\\n\\r\\n ///////////////////////////////////////////////\\r\\n // 512 by 256 division.\\r\\n ///////////////////////////////////////////////\\r\\n\\r\\n // Make division exact by subtracting the remainder from [prod1 prod0]\\r\\n // Compute remainder using mulmod\\r\\n uint remainder;\\r\\n assembly {\\r\\n remainder := mulmod(a, b, denominator)\\r\\n }\\r\\n // Subtract 256 bit number from 512 bit number\\r\\n assembly {\\r\\n prod1 := sub(prod1, gt(remainder, prod0))\\r\\n prod0 := sub(prod0, remainder)\\r\\n }\\r\\n\\r\\n // Factor powers of two out of denominator\\r\\n // Compute largest power of two divisor of denominator.\\r\\n // Always >= 1.\\r\\n // EDIT for 0.8 compatibility:\\r\\n // see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint\\r\\n uint twos = denominator & (~denominator + 1);\\r\\n\\r\\n // Divide denominator by power of two\\r\\n assembly {\\r\\n denominator := div(denominator, twos)\\r\\n }\\r\\n\\r\\n // Divide [prod1 prod0] by the factors of two\\r\\n assembly {\\r\\n prod0 := div(prod0, twos)\\r\\n }\\r\\n // Shift in bits from prod1 into prod0. For this we need\\r\\n // to flip `twos` such that it is 2**256 / twos.\\r\\n // If twos is zero, then it becomes one\\r\\n assembly {\\r\\n twos := add(div(sub(0, twos), twos), 1)\\r\\n }\\r\\n prod0 |= prod1 * twos;\\r\\n\\r\\n // Invert denominator mod 2**256\\r\\n // Now that denominator is an odd number, it has an inverse\\r\\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\\r\\n // Compute the inverse by starting with a seed that is correct\\r\\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\\r\\n uint inv = (3 * denominator) ^ 2;\\r\\n // Now use Newton-Raphson iteration to improve the precision.\\r\\n // Thanks to Hensel's lifting lemma, this also works in modular\\r\\n // arithmetic, doubling the correct bits in each step.\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**8\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**16\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**32\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**64\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**128\\r\\n inv *= 2 - denominator * inv;\\r\\n // inverse mod 2**256\\r\\n\\r\\n // Because the division is now exact we can divide by multiplying\\r\\n // with the modular inverse of denominator. This will give us the\\r\\n // correct result modulo 2**256. Since the precoditions guarantee\\r\\n // that the outcome is less than 2**256, this is the final result.\\r\\n // We don't need to compute the high bits of the result and prod1\\r\\n // is no longer required.\\r\\n result = prod0 * inv;\\r\\n return result;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates ceil(a\\u00d7b\\u00f7denominator) with full precision. Throws if result overflows a uint or denominator == 0\\r\\n /// @param a The multiplicand\\r\\n /// @param b The multiplier\\r\\n /// @param denominator The divisor\\r\\n /// @return result The 256-bit result\\r\\n function mulDivRoundingUp(\\r\\n uint a,\\r\\n uint b,\\r\\n uint denominator\\r\\n ) internal pure returns (uint result) {\\r\\n result = mulDiv(a, b, denominator);\\r\\n if (mulmod(a, b, denominator) > 0) {\\r\\n require(result < type(uint).max);\\r\\n result++;\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates price in pool\\r\\n /// @return price with decimals of paired token\\r\\n function getPrice(address pool_, address tokenIn) public view returns (uint) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(pool_);\\r\\n address token0 = pool.token0();\\r\\n address token1 = pool.token1();\\r\\n\\r\\n uint tokenInDecimals = tokenIn == token0 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n uint tokenOutDecimals = tokenIn == token1 ? IERC20Metadata(token0).decimals() : IERC20Metadata(token1).decimals();\\r\\n (uint160 sqrtPriceX96,,,,,,) = pool.slot0();\\r\\n\\r\\n uint divider = tokenOutDecimals < 18 ? _max(10 ** tokenOutDecimals / 10 ** tokenInDecimals, 1) : 1;\\r\\n\\r\\n uint priceDigits = _countDigits(uint(sqrtPriceX96));\\r\\n uint purePrice;\\r\\n uint precision;\\r\\n if (tokenIn == token0) {\\r\\n precision = 10 ** ((priceDigits < 29 ? 29 - priceDigits : 0) + tokenInDecimals);\\r\\n uint part = uint(sqrtPriceX96) * precision / TWO_96;\\r\\n purePrice = part * part;\\r\\n } else {\\r\\n precision = 10 ** ((priceDigits > 29 ? priceDigits - 29 : 0) + tokenInDecimals);\\r\\n uint part = TWO_96 * precision / uint(sqrtPriceX96);\\r\\n purePrice = part * part;\\r\\n }\\r\\n return purePrice / divider / precision / (precision > 1e18 ? (precision / 1e18) : 1);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token0 and price range\\r\\n /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount0 The amount0 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount0(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount0) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n uint intermediate = mulDiv(sqrtRatioAX96, sqrtRatioBX96, Q96);\\r\\n return _toUint128(mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of liquidity received for a given amount of token1 and price range\\r\\n /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param amount1 The amount1 being sent in\\r\\n /// @return liquidity The amount of returned liquidity\\r\\n function _getLiquidityForAmount1(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint amount1) internal pure returns (uint128 liquidity) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return _toUint128(mulDiv(amount1, Q96, sqrtRatioBX96 - sqrtRatioAX96));\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token0 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount0 The amount0\\r\\n function _getAmount0ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount0) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(1, mulDivRoundingUp(uint(liquidity) << RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96), sqrtRatioAX96);\\r\\n }\\r\\n\\r\\n /// @notice Computes the amount of token1 for a given amount of liquidity and a price range\\r\\n /// @param sqrtRatioAX96 A sqrt price\\r\\n /// @param sqrtRatioBX96 Another sqrt price\\r\\n /// @param liquidity The liquidity being valued\\r\\n /// @return amount1 The amount1\\r\\n function _getAmount1ForLiquidity(uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity) internal pure returns (uint amount1) {\\r\\n if (sqrtRatioAX96 > sqrtRatioBX96) {\\r\\n (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);\\r\\n }\\r\\n return mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Q96);\\r\\n }\\r\\n\\r\\n function _computeFeesEarned(\\r\\n PoolPosition memory position,\\r\\n bool isZero,\\r\\n uint feeGrowthInsideLast,\\r\\n int24 tick\\r\\n ) internal view returns (uint fee) {\\r\\n IUniswapV3Pool pool = IUniswapV3Pool(position.pool);\\r\\n uint feeGrowthOutsideLower;\\r\\n uint feeGrowthOutsideUpper;\\r\\n uint feeGrowthGlobal;\\r\\n if (isZero) {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal0X128();\\r\\n (,, feeGrowthOutsideLower,,,,,) = pool.ticks(position.lowerTick);\\r\\n (,, feeGrowthOutsideUpper,,,,,) = pool.ticks(position.upperTick);\\r\\n } else {\\r\\n feeGrowthGlobal = pool.feeGrowthGlobal1X128();\\r\\n (,,, feeGrowthOutsideLower,,,,) = pool.ticks(position.lowerTick);\\r\\n (,,, feeGrowthOutsideUpper,,,,) = pool.ticks(position.upperTick);\\r\\n }\\r\\n\\r\\n unchecked {\\r\\n // calculate fee growth below\\r\\n uint feeGrowthBelow;\\r\\n if (tick >= position.lowerTick) {\\r\\n feeGrowthBelow = feeGrowthOutsideLower;\\r\\n } else {\\r\\n feeGrowthBelow = feeGrowthGlobal - feeGrowthOutsideLower;\\r\\n }\\r\\n\\r\\n // calculate fee growth above\\r\\n uint feeGrowthAbove;\\r\\n if (tick < position.upperTick) {\\r\\n feeGrowthAbove = feeGrowthOutsideUpper;\\r\\n } else {\\r\\n feeGrowthAbove = feeGrowthGlobal - feeGrowthOutsideUpper;\\r\\n }\\r\\n\\r\\n uint feeGrowthInside =\\r\\n feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove;\\r\\n fee = mulDiv(\\r\\n position.liquidity,\\r\\n feeGrowthInside - feeGrowthInsideLast,\\r\\n 0x100000000000000000000000000000000\\r\\n );\\r\\n }\\r\\n }\\r\\n\\r\\n /// @notice Calculates sqrt(1.0001^tick) * 2^96\\r\\n /// @dev Throws if |tick| > max tick\\r\\n /// @param tick The input tick for the above formula\\r\\n /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\\r\\n /// at the given tick\\r\\n function _getSqrtRatioAtTick(int24 tick)\\r\\n internal\\r\\n pure\\r\\n returns (uint160 sqrtPriceX96)\\r\\n {\\r\\n uint256 absTick =\\r\\n tick < 0 ? uint256(- int256(tick)) : uint256(int256(tick));\\r\\n\\r\\n // EDIT: 0.8 compatibility\\r\\n require(absTick <= uint256(int256(MAX_TICK)), \\\"T\\\");\\r\\n\\r\\n uint256 ratio =\\r\\n absTick & 0x1 != 0\\r\\n ? 0xfffcb933bd6fad37aa2d162d1a594001\\r\\n : 0x100000000000000000000000000000000;\\r\\n if (absTick & 0x2 != 0)\\r\\n ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\\r\\n if (absTick & 0x4 != 0)\\r\\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\\r\\n if (absTick & 0x8 != 0)\\r\\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\\r\\n if (absTick & 0x10 != 0)\\r\\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\\r\\n if (absTick & 0x20 != 0)\\r\\n ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\\r\\n if (absTick & 0x40 != 0)\\r\\n ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\\r\\n if (absTick & 0x80 != 0)\\r\\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\\r\\n if (absTick & 0x100 != 0)\\r\\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\\r\\n if (absTick & 0x200 != 0)\\r\\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\\r\\n if (absTick & 0x400 != 0)\\r\\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\\r\\n if (absTick & 0x800 != 0)\\r\\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\\r\\n if (absTick & 0x1000 != 0)\\r\\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\\r\\n if (absTick & 0x2000 != 0)\\r\\n ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\\r\\n if (absTick & 0x4000 != 0)\\r\\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\\r\\n if (absTick & 0x8000 != 0)\\r\\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\\r\\n if (absTick & 0x10000 != 0)\\r\\n ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\\r\\n if (absTick & 0x20000 != 0)\\r\\n ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\\r\\n if (absTick & 0x40000 != 0)\\r\\n ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\\r\\n if (absTick & 0x80000 != 0)\\r\\n ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\\r\\n\\r\\n if (tick > 0) ratio = type(uint256).max / ratio;\\r\\n\\r\\n // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\\r\\n // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\\r\\n // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\\r\\n sqrtPriceX96 = uint160(\\r\\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\\r\\n );\\r\\n }\\r\\n\\r\\n /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\\r\\n /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\\r\\n /// ever return.\\r\\n /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\\r\\n /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\\r\\n function _getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // second inequality must be < because the price can never reach the price at the max tick\\r\\n require(\\r\\n sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,\\r\\n \\\"R\\\"\\r\\n );\\r\\n uint256 ratio = uint256(sqrtPriceX96) << 32;\\r\\n\\r\\n uint256 r = ratio;\\r\\n uint256 msb = 0;\\r\\n\\r\\n assembly {\\r\\n let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(5, gt(r, 0xFFFFFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(4, gt(r, 0xFFFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(3, gt(r, 0xFF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(2, gt(r, 0xF))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := shl(1, gt(r, 0x3))\\r\\n msb := or(msb, f)\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n let f := gt(r, 0x1)\\r\\n msb := or(msb, f)\\r\\n }\\r\\n\\r\\n if (msb >= 128) r = ratio >> (msb - 127);\\r\\n else r = ratio << (127 - msb);\\r\\n\\r\\n int256 log_2 = (int256(msb) - 128) << 64;\\r\\n\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(63, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(62, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(61, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(60, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(59, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(58, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(57, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(56, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(55, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(54, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(53, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(52, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(51, f))\\r\\n r := shr(f, r)\\r\\n }\\r\\n assembly {\\r\\n r := shr(127, mul(r, r))\\r\\n let f := shr(128, r)\\r\\n log_2 := or(log_2, shl(50, f))\\r\\n }\\r\\n\\r\\n tick = _getFinalTick(log_2, sqrtPriceX96);\\r\\n }\\r\\n\\r\\n function _getFinalTick(int256 log_2, uint160 sqrtPriceX96) internal pure returns (int24 tick) {\\r\\n // 128.128 number\\r\\n int256 log_sqrt10001 = log_2 * 255738958999603826347141;\\r\\n\\r\\n int24 tickLow =\\r\\n int24(\\r\\n (log_sqrt10001 - 3402992956809132418596140100660247210) >> 128\\r\\n );\\r\\n int24 tickHi =\\r\\n int24(\\r\\n (log_sqrt10001 + 291339464771989622907027621153398088495) >> 128\\r\\n );\\r\\n\\r\\n tick = (tickLow == tickHi)\\r\\n ? tickLow\\r\\n : (_getSqrtRatioAtTick(tickHi) <= sqrtPriceX96\\r\\n ? tickHi\\r\\n : tickLow);\\r\\n }\\r\\n\\r\\n function _getPositionId(PoolPosition memory position) internal pure returns (bytes32) {\\r\\n return keccak256(abi.encodePacked(position.owner, position.lowerTick, position.upperTick));\\r\\n }\\r\\n\\r\\n function _countDigits(uint n) internal pure returns (uint) {\\r\\n if (n == 0) {\\r\\n return 0;\\r\\n }\\r\\n uint count = 0;\\r\\n while (n != 0) {\\r\\n n = n / 10;\\r\\n ++count;\\r\\n }\\r\\n return count;\\r\\n }\\r\\n\\r\\n function _min(uint a, uint b) internal pure returns (uint) {\\r\\n return a < b ? a : b;\\r\\n }\\r\\n\\r\\n function _max(uint a, uint b) internal pure returns (uint) {\\r\\n return a > b ? a : b;\\r\\n }\\r\\n\\r\\n function _toUint128(uint x) private pure returns (uint128 y) {\\r\\n require((y = uint128(x)) == x);\\r\\n }\\r\\n}\\r\\n\",\"keccak256\":\"0x9c70a022b0ea88d21f5400145a8b256c37a12659b8c4971871d696620a9b1505\",\"license\":\"BUSL-1.1\"}},\"version\":1}", + "bytecode": "0x610db261003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806317b13c951461005b5780636c55a3ca14610086578063e4ee4bf7146100b3578063f8328d9f146100d5575b600080fd5b61006e6100693660046108c7565b6100eb565b60405160029190910b81526020015b60405180910390f35b6100996100943660046108fa565b61015c565b60408051600293840b81529190920b60208201520161007d565b8180156100bf57600080fd5b506100d36100ce36600461095c565b610200565b005b6100dd606481565b60405190815260200161007d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014f91906109ff565b5093979650505050505050565b6000807306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe3963cd8e20e7610182876100eb565b6040516001600160e01b031960e084901b168152600291820b600482015287820b60248201529086900b60448201526064016040805180830381865af41580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610a83565b91509150935093915050565b60038601546000908190610236908490600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b6102ed565b895460038b0154929450909250600091829161026b916001600160a01b039091169086908690600160a81b900460ff166103b7565b90925090506102a48b8b8b8b8b8b610283888a610ad3565b610295670de0b6b3a76400008b610ae6565b61029f9190610b13565b6106ab565b5050600397909701805465ffffffffffff60c81b1916600160e01b62ffffff998a160262ffffff60c81b191617600160c81b929098169190910296909617909555505050505050565b600080806102fb8686610b27565b905060008460020b8260020b1461031c57610317600283610b4c565b61031f565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b60448201529091507306901AdA06F58d1C6bF8d087DA6085a0Ab7eBe399063cd8e20e7906064016040805180830381865af4158015610384573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a89190610a83565b93509350505094509492505050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041e9190610b86565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073D398438a52fD230195861b9Af0B4Ab8e9b0006F29063ac41865a90604401602060405180830381865af4158015610484573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a89190610ba3565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190610bbc565b60ff16905081600061052183600a610cbb565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152909150816105725760405162461bcd60e51b81526004016105699190610cc7565b60405180910390fd5b506040516305f08b0f60e21b81526001600160a01b038c16600482015260028b810b60248301528a900b60448201526064810183905260848101829052600090819073D398438a52fD230195861b9Af0B4Ab8e9b0006F2906317c22c3c9060a401606060405180830381865af41580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106149190610d15565b50915091508961065d5761063082670de0b6b3a7640000610ae6565b838761064484670de0b6b3a7640000610ae6565b61064e9190610ae6565b6106589190610b13565b610697565b828661067183670de0b6b3a7640000610ae6565b61067b9190610ae6565b6106859190610b13565b61069783670de0b6b3a7640000610ae6565b985098505050505050505094509492505050565b600286015460038701546001600160a01b0391821691167346aa135654F8A46cDF029059c531EfBd273682206343f8b62c6106e960208c018c6108c7565b6106f960408d0160208e016108c7565b60405160e084901b6001600160e01b03191681526001600160a01b03928316600482015290821660248201528186166044820152908416606482015260848101869052863560a4820152602087013560c482015260e481018a90526101040160006040518083038186803b15801561077057600080fd5b505af4158015610784573d6000803e3d6000fd5b50505050866000146108a4576040516370a0823160e01b815230600482015273C92346a144fa75b45b0eDAe966FEAA0E30C82c559063890ffb849084908a9089908b906001600160a01b038516906370a0823190602401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610ba3565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af415801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190610d58565b50505b505050505050505050565b6001600160a01b03811681146108c457600080fd5b50565b6000602082840312156108d957600080fd5b81356108e4816108af565b9392505050565b8060020b81146108c457600080fd5b60008060006060848603121561090f57600080fd5b833561091a816108af565b9250602084013561092a816108eb565b9150604084013561093a816108eb565b809150509250925092565b806040810183101561095657600080fd5b92915050565b6000806000806000806000610120888a03121561097857600080fd5b6109828989610945565b965060408801359550606088013594506080880135935060a08801356109a7816108af565b92506109b68960c08a01610945565b91506101008801356109c7816108eb565b8091505092959891949750929550565b805161ffff811681146109e957600080fd5b919050565b805160ff811681146109e957600080fd5b600080600080600080600060e0888a031215610a1a57600080fd5b8751610a25816108af565b6020890151909750610a36816108eb565b9550610a44604089016109d7565b9450610a52606089016109d7565b9350610a60608089016109d7565b9250610a6e60a089016109ee565b915060c088015180151581146109c757600080fd5b60008060408385031215610a9657600080fd5b8251610aa1816108eb565b6020840151909250610ab2816108eb565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561095657610956610abd565b808202811582820484141761095657610956610abd565b634e487b7160e01b600052601260045260246000fd5b600082610b2257610b22610afd565b500490565b600282810b9082900b03627fffff198112627fffff8213171561095657610956610abd565b60008160020b8360020b80610b6357610b63610afd565b627fffff19821460001982141615610b7d57610b7d610abd565b90059392505050565b600060208284031215610b9857600080fd5b81516108e4816108af565b600060208284031215610bb557600080fd5b5051919050565b600060208284031215610bce57600080fd5b6108e4826109ee565b600181815b80851115610c12578160001904821115610bf857610bf8610abd565b80851615610c0557918102915b93841c9390800290610bdc565b509250929050565b600082610c2957506001610956565b81610c3657506000610956565b8160018114610c4c5760028114610c5657610c72565b6001915050610956565b60ff841115610c6757610c67610abd565b50506001821b610956565b5060208310610133831016604e8410600b8410161715610c95575081810a610956565b610c9f8383610bd7565b8060001904821115610cb357610cb3610abd565b029392505050565b60006108e48383610c1a565b600060208083528351808285015260005b81811015610cf457858101830151858201604001528201610cd8565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600060608486031215610d2a57600080fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff8116811461093a57600080fd5b60008060408385031215610d6b57600080fd5b50508051602090910151909290915056fea2646970667358221220920aa26c319e434a406624bb90daf7b088922ac7ac2af424db7a9ed9465116c164736f6c63430008110033", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100565760003560e01c806317b13c951461005b5780636c55a3ca14610086578063e4ee4bf7146100b3578063f8328d9f146100d5575b600080fd5b61006e6100693660046108c7565b6100eb565b60405160029190910b81526020015b60405180910390f35b6100996100943660046108fa565b61015c565b60408051600293840b81529190920b60208201520161007d565b8180156100bf57600080fd5b506100d36100ce36600461095c565b610200565b005b6100dd606481565b60405190815260200161007d565b6000816001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa15801561012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014f91906109ff565b5093979650505050505050565b60008073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__63cd8e20e7610182876100eb565b6040516001600160e01b031960e084901b168152600291820b600482015287820b60248201529086900b60448201526064016040805180830381865af41580156101d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101f49190610a83565b91509150935093915050565b60038601546000908190610236908490600160c81b8104600290810b91600160e01b8104820b91600160b01b909104900b6102ed565b895460038b0154929450909250600091829161026b916001600160a01b039091169086908690600160a81b900460ff166103b7565b90925090506102a48b8b8b8b8b8b610283888a610ad3565b610295670de0b6b3a76400008b610ae6565b61029f9190610b13565b6106ab565b5050600397909701805465ffffffffffff60c81b1916600160e01b62ffffff998a160262ffffff60c81b191617600160c81b929098169190910296909617909555505050505050565b600080806102fb8686610b27565b905060008460020b8260020b1461031c57610317600283610b4c565b61031f565b60005b60405163cd8e20e760e01b815260028a810b600483015282810b602483015287900b604482015290915073__$b1ba452cecccdd06eb05ace2d0a762c7e1$__9063cd8e20e7906064016040805180830381865af4158015610384573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a89190610a83565b93509350505094509492505050565b6000806000866001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061041e9190610b86565b604051635620c32d60e11b81526001600160a01b03808a1660048301528216602482015290915060009073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__9063ac41865a90604401602060405180830381865af4158015610484573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a89190610ba3565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050e9190610bbc565b60ff16905081600061052183600a610cbb565b60408051808201909152601081526f54532d3234207a65726f2076616c756560801b6020820152909150816105725760405162461bcd60e51b81526004016105699190610cc7565b60405180910390fd5b506040516305f08b0f60e21b81526001600160a01b038c16600482015260028b810b60248301528a900b60448201526064810183905260848101829052600090819073__$0c70757f598a889e7e5bdfcf0bf5e1f3f7$__906317c22c3c9060a401606060405180830381865af41580156105f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106149190610d15565b50915091508961065d5761063082670de0b6b3a7640000610ae6565b838761064484670de0b6b3a7640000610ae6565b61064e9190610ae6565b6106589190610b13565b610697565b828661067183670de0b6b3a7640000610ae6565b61067b9190610ae6565b6106859190610b13565b61069783670de0b6b3a7640000610ae6565b985098505050505050505094509492505050565b600286015460038701546001600160a01b03918216911673__$295fb458e6648e6381ea46363bb426e5e7$__6343f8b62c6106e960208c018c6108c7565b6106f960408d0160208e016108c7565b60405160e084901b6001600160e01b03191681526001600160a01b03928316600482015290821660248201528186166044820152908416606482015260848101869052863560a4820152602087013560c482015260e481018a90526101040160006040518083038186803b15801561077057600080fd5b505af4158015610784573d6000803e3d6000fd5b50505050866000146108a4576040516370a0823160e01b815230600482015273__$8f1afe7577f9ab973017c74eca19b86f3c$__9063890ffb849084908a9089908b906001600160a01b038516906370a0823190602401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610ba3565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015260248101949094529390911660448301526064820152608481019190915260a4016040805180830381865af415801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190610d58565b50505b505050505050505050565b6001600160a01b03811681146108c457600080fd5b50565b6000602082840312156108d957600080fd5b81356108e4816108af565b9392505050565b8060020b81146108c457600080fd5b60008060006060848603121561090f57600080fd5b833561091a816108af565b9250602084013561092a816108eb565b9150604084013561093a816108eb565b809150509250925092565b806040810183101561095657600080fd5b92915050565b6000806000806000806000610120888a03121561097857600080fd5b6109828989610945565b965060408801359550606088013594506080880135935060a08801356109a7816108af565b92506109b68960c08a01610945565b91506101008801356109c7816108eb565b8091505092959891949750929550565b805161ffff811681146109e957600080fd5b919050565b805160ff811681146109e957600080fd5b600080600080600080600060e0888a031215610a1a57600080fd5b8751610a25816108af565b6020890151909750610a36816108eb565b9550610a44604089016109d7565b9450610a52606089016109d7565b9350610a60608089016109d7565b9250610a6e60a089016109ee565b915060c088015180151581146109c757600080fd5b60008060408385031215610a9657600080fd5b8251610aa1816108eb565b6020840151909250610ab2816108eb565b809150509250929050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561095657610956610abd565b808202811582820484141761095657610956610abd565b634e487b7160e01b600052601260045260246000fd5b600082610b2257610b22610afd565b500490565b600282810b9082900b03627fffff198112627fffff8213171561095657610956610abd565b60008160020b8360020b80610b6357610b63610afd565b627fffff19821460001982141615610b7d57610b7d610abd565b90059392505050565b600060208284031215610b9857600080fd5b81516108e4816108af565b600060208284031215610bb557600080fd5b5051919050565b600060208284031215610bce57600080fd5b6108e4826109ee565b600181815b80851115610c12578160001904821115610bf857610bf8610abd565b80851615610c0557918102915b93841c9390800290610bdc565b509250929050565b600082610c2957506001610956565b81610c3657506000610956565b8160018114610c4c5760028114610c5657610c72565b6001915050610956565b60ff841115610c6757610c67610abd565b50506001821b610956565b5060208310610133831016604e8410600b8410161715610c95575081810a610956565b610c9f8383610bd7565b8060001904821115610cb357610cb3610abd565b029392505050565b60006108e48383610c1a565b600060208083528351808285015260005b81811015610cf457858101830151858201604001528201610cd8565b506000604082860101526040601f19601f8301168501019250505092915050565b600080600060608486031215610d2a57600080fd5b835192506020840151915060408401516fffffffffffffffffffffffffffffffff8116811461093a57600080fd5b60008060408385031215610d6b57600080fd5b50508051602090910151909290915056fea2646970667358221220920aa26c319e434a406624bb90daf7b088922ac7ac2af424db7a9ed9465116c164736f6c63430008110033", "libraries": { "UniswapV3Lib": "0xD398438a52fD230195861b9Af0B4Ab8e9b0006F2", "ConverterStrategyBaseLib2": "0xC92346a144fa75b45b0eDAe966FEAA0E30C82c55", - "BorrowLib": "0xd84c6293b2E190DDd7Ea7F6E00396A840294BDcE", - "PairBasedStrategyLogicLib": "0xB2dD88095aFe40481C4969f8761DE3D6BC08D222" + "BorrowLib": "0x46aa135654F8A46cDF029059c531EfBd27368220", + "PairBasedStrategyLogicLib": "0x06901AdA06F58d1C6bF8d087DA6085a0Ab7eBe39" }, "devdoc": { "kind": "dev", diff --git a/package-lock.json b/package-lock.json index e5893a03..8f07f111 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "ethereumjs-tx": "^2.1.2", "ethers": "5.7.2", "graphql": "^16.6.0", - "hardhat": "2.14.1", + "hardhat": "2.22.2", "hardhat-abi-exporter": "^2.10.1", "hardhat-change-network": "^0.0.7", "hardhat-contract-sizer": "^2.8.0", @@ -2143,6 +2143,160 @@ "node": ">= 8" } }, + "node_modules/@nomicfoundation/edr": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.3.tgz", + "integrity": "sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ==", + "engines": { + "node": ">= 18" + }, + "optionalDependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.3.3", + "@nomicfoundation/edr-darwin-x64": "0.3.3", + "@nomicfoundation/edr-linux-arm64-gnu": "0.3.3", + "@nomicfoundation/edr-linux-arm64-musl": "0.3.3", + "@nomicfoundation/edr-linux-x64-gnu": "0.3.3", + "@nomicfoundation/edr-linux-x64-musl": "0.3.3", + "@nomicfoundation/edr-win32-arm64-msvc": "0.3.3", + "@nomicfoundation/edr-win32-ia32-msvc": "0.3.3", + "@nomicfoundation/edr-win32-x64-msvc": "0.3.3" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz", + "integrity": "sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz", + "integrity": "sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz", + "integrity": "sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz", + "integrity": "sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz", + "integrity": "sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz", + "integrity": "sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-arm64-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz", + "integrity": "sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/edr-win32-ia32-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz", + "integrity": "sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz", + "integrity": "sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 18" + } + }, "node_modules/@nomicfoundation/ethereumjs-block": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", @@ -2160,6 +2314,72 @@ "node": ">=14" } }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, "node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -2205,29 +2425,15 @@ "node": ">=14" } }, - "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" + "@chainsafe/as-sha256": "^0.3.1" } }, - "node_modules/@nomicfoundation/ethereumjs-common": { + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@nomicfoundation/ethereumjs-common": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", @@ -2236,63 +2442,56 @@ "crc-32": "^1.2.0" } }, - "node_modules/@nomicfoundation/ethereumjs-ethash": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", - "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.1", + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", "@nomicfoundation/ethereumjs-rlp": "5.0.1", "@nomicfoundation/ethereumjs-util": "9.0.1", - "abstract-level": "^1.0.3", - "bigint-crypto-utils": "^3.0.23", "ethereum-cryptography": "0.1.3" }, "engines": { "node": ">=14" } }, - "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@nomicfoundation/ethereumjs-evm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", - "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", "dependencies": { - "@ethersproject/providers": "^5.7.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" }, "engines": { "node": ">=14" } }, - "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", @@ -2314,7 +2513,129 @@ "setimmediate": "^1.0.5" } }, - "node_modules/@nomicfoundation/ethereumjs-rlp": { + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", + "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", + "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@nomicfoundation/ethereumjs-rlp": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", @@ -2325,6 +2646,77 @@ "node": ">=14" } }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@nomicfoundation/ethereumjs-statemanager": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", @@ -2338,6 +2730,56 @@ "js-sdsl": "^4.1.4" } }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -2375,6 +2817,47 @@ "node": ">=14" } }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -2398,19 +2881,25 @@ } }, "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", - "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", "dependencies": { - "@chainsafe/ssz": "^0.9.2", - "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", "ethereum-cryptography": "0.1.3" }, "engines": { - "node": ">=14" + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } } }, "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { @@ -2436,33 +2925,23 @@ } }, "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", - "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", "dependencies": { - "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", "ethereum-cryptography": "0.1.3" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/persistent-merkle-tree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", - "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", - "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.5.0" + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } } }, "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { @@ -2510,6 +2989,72 @@ "node": ">=14" } }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -3416,6 +3961,127 @@ "node": "18.x.x" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "dependencies": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@nomiclabs/hardhat-solhint": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-solhint/-/hardhat-solhint-2.0.1.tgz", @@ -3427,6 +4093,37 @@ "hardhat": "^2.0.0" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", @@ -3438,6 +4135,14 @@ "node": ">=0.4.0" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3654,6 +4359,17 @@ "node": ">=4" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -3665,6 +4381,17 @@ "node": ">=4" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -3691,6 +4418,81 @@ "node": ">=4" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/hardhat": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", + "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -3724,6 +4526,14 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3736,6 +4546,18 @@ "node": ">= 0.8.0" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -3752,6 +4574,28 @@ "node": ">= 0.8.0" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -3764,6 +4608,14 @@ "node": ">=4" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -3851,6 +4703,53 @@ "node": ">=6" } }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/solc/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/@tetu_io/tetu-contracts-v2/node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/@tetu_io/tetu-contracts-v2/node_modules/solhint": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/solhint/-/solhint-2.3.1.tgz", @@ -4027,706 +4926,114 @@ "node": "^18.x.x" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@chainsafe/persistent-merkle-tree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", - "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "node_modules/@tetu_io/tetu-converter/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-block": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", - "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=14" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "node_modules/@tetu_io/tetu-converter/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-blockchain": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", - "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", + "node_modules/@tetu_io/tetu-converter/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-ethash": "3.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "level": "^8.0.0", - "lru-cache": "^5.1.1", - "memory-level": "^1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=14" + "node": ">=7.0.0" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "node_modules/@tetu_io/tetu-converter/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy": { + "version": "0.11.45", + "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz", + "integrity": "sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==", "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/providers": "^5.7.2", + "@ethersproject/solidity": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wallet": "^5.7.0", + "@types/qs": "^6.9.7", + "axios": "^0.21.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "ethers": "^5.7.0", + "form-data": "^4.0.0", + "fs-extra": "^10.0.0", + "match-all": "^1.2.6", + "murmur-128": "^0.2.1", + "qs": "^6.9.4", + "zksync-web3": "^0.14.3" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-common": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", - "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", + "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "dependencies": { - "@nomicfoundation/ethereumjs-util": "9.0.2", - "crc-32": "^1.2.0" + "follow-redirects": "^1.14.0" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-ethash": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", - "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", + "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "bigint-crypto-utils": "^3.0.23", - "ethereum-cryptography": "0.1.3" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" + "node": ">=12" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-evm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", - "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", + "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-tracer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/hardhat-tracer/-/hardhat-tracer-1.3.0.tgz", + "integrity": "sha512-mUYuRJWlxCwY4R2urCpNM4ecVSq/iMLiVP9YZKlfXyv4R8T+4HAcTfumilUOXHGe6wHI+8Ki2EaTon3KgzATDA==", "dependencies": { - "@ethersproject/providers": "^5.7.1", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" + "ethers": "^5.6.1" }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", - "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-statemanager": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", - "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1", - "js-sdsl": "^4.1.4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-trie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", - "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", - "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@types/readable-stream": "^2.3.13", - "ethereum-cryptography": "0.1.3", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-trie/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", - "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", - "dependencies": { - "@chainsafe/ssz": "^0.9.2", - "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", - "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", - "dependencies": { - "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-util/node_modules/@chainsafe/ssz": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", - "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", - "dependencies": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.5.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-vm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", - "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", - "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@nomicfoundation/ethereumjs-vm/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@tetu_io/tetu-converter/node_modules/commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" - }, - "node_modules/@tetu_io/tetu-converter/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat": { - "version": "2.19.4", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.19.4.tgz", - "integrity": "sha512-fTQJpqSt3Xo9Mn/WrdblNGAfcANM6XC3tAEi6YogB4s02DmTf93A8QsGb8uR0KR8TFcpcS8lgiW4ugAIYpnbrQ==", - "dependencies": { - "@ethersproject/abi": "^5.1.2", - "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@nomicfoundation/ethereumjs-vm": "7.0.2", - "@nomicfoundation/solidity-analyzer": "^0.1.0", - "@sentry/node": "^5.18.1", - "@types/bn.js": "^5.1.0", - "@types/lru-cache": "^5.1.0", - "adm-zip": "^0.4.16", - "aggregate-error": "^3.0.0", - "ansi-escapes": "^4.3.0", - "chalk": "^2.4.2", - "chokidar": "^3.4.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "ethereumjs-abi": "^0.6.8", - "find-up": "^2.1.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "glob": "7.2.0", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.7.3", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tsort": "0.0.1", - "undici": "^5.14.0", - "uuid": "^8.3.2", - "ws": "^7.4.6" - }, - "bin": { - "hardhat": "internal/cli/bootstrap.js" - }, - "peerDependencies": { - "ts-node": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy": { - "version": "0.11.45", - "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz", - "integrity": "sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==", - "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/contracts": "^5.7.0", - "@ethersproject/providers": "^5.7.2", - "@ethersproject/solidity": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wallet": "^5.7.0", - "@types/qs": "^6.9.7", - "axios": "^0.21.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "debug": "^4.3.2", - "enquirer": "^2.3.6", - "ethers": "^5.7.0", - "form-data": "^4.0.0", - "fs-extra": "^10.0.0", - "match-all": "^1.2.6", - "murmur-128": "^0.2.1", - "qs": "^6.9.4", - "zksync-web3": "^0.14.3" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy/node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dependencies": { - "follow-redirects": "^1.14.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-deploy/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat-tracer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/hardhat-tracer/-/hardhat-tracer-1.3.0.tgz", - "integrity": "sha512-mUYuRJWlxCwY4R2urCpNM4ecVSq/iMLiVP9YZKlfXyv4R8T+4HAcTfumilUOXHGe6wHI+8Ki2EaTon3KgzATDA==", - "dependencies": { - "ethers": "^5.6.1" - }, - "peerDependencies": { - "chalk": "4.x", - "ethers": "5.x", - "hardhat": "2.x" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/hardhat/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "peerDependencies": { + "chalk": "4.x", + "ethers": "5.x", + "hardhat": "2.x" } }, "node_modules/@tetu_io/tetu-converter/node_modules/has-flag": { @@ -4748,117 +5055,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@tetu_io/tetu-converter/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/solc": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", - "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", - "dependencies": { - "command-exists": "^1.2.8", - "commander": "3.0.2", - "follow-redirects": "^1.12.1", - "fs-extra": "^0.30.0", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "require-from-string": "^2.0.0", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "bin": { - "solcjs": "solcjs" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/solc/node_modules/fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/solc/node_modules/jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@tetu_io/tetu-converter/node_modules/solc/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "bin": { - "semver": "bin/semver" - } - }, "node_modules/@tetu_io/tetu-converter/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6975,9 +7171,9 @@ "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" }, "node_modules/abstract-level": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", - "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.4.tgz", + "integrity": "sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg==", "dependencies": { "buffer": "^6.0.3", "catering": "^2.1.0", @@ -7155,6 +7351,14 @@ "node": ">=0.4.2" } }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -7612,6 +7816,91 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -8166,9 +8455,9 @@ "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" }, "node_modules/classic-level": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", - "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.4.1.tgz", + "integrity": "sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ==", "hasInstallScript": true, "dependencies": { "abstract-level": "^1.0.2", @@ -8200,6 +8489,17 @@ "node": ">=6" } }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -19631,30 +19931,24 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/hardhat": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", - "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.2.tgz", + "integrity": "sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw==", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-blockchain": "7.0.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-evm": "2.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-statemanager": "2.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", - "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", "@types/lru-cache": "^5.1.0", - "abort-controller": "^3.0.0", "adm-zip": "^0.4.16", "aggregate-error": "^3.0.0", "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", "chalk": "^2.4.2", "chokidar": "^3.4.0", "ci-info": "^2.0.0", @@ -19674,7 +19968,6 @@ "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", - "qs": "^6.7.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", @@ -19689,9 +19982,6 @@ "bin": { "hardhat": "internal/cli/bootstrap.js" }, - "engines": { - "node": ">=14.0.0" - }, "peerDependencies": { "ts-node": "*", "typescript": "*" @@ -21411,10 +21701,11 @@ } }, "node_modules/level": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", - "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.1.tgz", + "integrity": "sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ==", "dependencies": { + "abstract-level": "^1.0.4", "browser-level": "^1.0.1", "classic-level": "^1.2.0" }, @@ -27618,6 +27909,17 @@ "node": ">=4" } }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", @@ -29309,6 +29611,76 @@ "fastq": "^1.6.0" } }, + "@nomicfoundation/edr": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.3.tgz", + "integrity": "sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ==", + "requires": { + "@nomicfoundation/edr-darwin-arm64": "0.3.3", + "@nomicfoundation/edr-darwin-x64": "0.3.3", + "@nomicfoundation/edr-linux-arm64-gnu": "0.3.3", + "@nomicfoundation/edr-linux-arm64-musl": "0.3.3", + "@nomicfoundation/edr-linux-x64-gnu": "0.3.3", + "@nomicfoundation/edr-linux-x64-musl": "0.3.3", + "@nomicfoundation/edr-win32-arm64-msvc": "0.3.3", + "@nomicfoundation/edr-win32-ia32-msvc": "0.3.3", + "@nomicfoundation/edr-win32-x64-msvc": "0.3.3" + } + }, + "@nomicfoundation/edr-darwin-arm64": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz", + "integrity": "sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ==", + "optional": true + }, + "@nomicfoundation/edr-darwin-x64": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz", + "integrity": "sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg==", + "optional": true + }, + "@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz", + "integrity": "sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA==", + "optional": true + }, + "@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz", + "integrity": "sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q==", + "optional": true + }, + "@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz", + "integrity": "sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA==", + "optional": true + }, + "@nomicfoundation/edr-linux-x64-musl": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz", + "integrity": "sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw==", + "optional": true + }, + "@nomicfoundation/edr-win32-arm64-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz", + "integrity": "sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA==", + "optional": true + }, + "@nomicfoundation/edr-win32-ia32-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz", + "integrity": "sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w==", + "optional": true + }, + "@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz", + "integrity": "sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w==", + "optional": true + }, "@nomicfoundation/ethereumjs-block": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", @@ -29323,6 +29695,62 @@ "ethers": "^5.7.1" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + } + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29367,6 +29795,62 @@ "memory-level": "^1.0.0" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + } + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29392,12 +29876,11 @@ } }, "@nomicfoundation/ethereumjs-common": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", - "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", "requires": { - "@nomicfoundation/ethereumjs-util": "9.0.1", - "crc-32": "^1.2.0" + "@nomicfoundation/ethereumjs-util": "9.0.4" } }, "@nomicfoundation/ethereumjs-ethash": { @@ -29413,6 +29896,38 @@ "ethereum-cryptography": "0.1.3" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29452,6 +29967,62 @@ "rustbn.js": "~0.2.0" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + } + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29477,9 +30048,9 @@ } }, "@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", - "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==" }, "@nomicfoundation/ethereumjs-statemanager": { "version": "2.0.1", @@ -29494,6 +30065,47 @@ "js-sdsl": "^4.1.4" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29530,6 +30142,38 @@ "readable-stream": "^3.6.0" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29555,15 +30199,13 @@ } }, "@nomicfoundation/ethereumjs-tx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", - "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", "requires": { - "@chainsafe/ssz": "^0.9.2", - "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", "ethereum-cryptography": "0.1.3" }, "dependencies": { @@ -29592,32 +30234,14 @@ } }, "@nomicfoundation/ethereumjs-util": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", - "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", "requires": { - "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", "ethereum-cryptography": "0.1.3" }, "dependencies": { - "@chainsafe/persistent-merkle-tree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", - "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", - "requires": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "@chainsafe/ssz": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", - "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", - "requires": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.5.0" - } - }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -29662,6 +30286,62 @@ "rustbn.js": "~0.2.0" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + } + } + }, "ethereum-cryptography": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", @@ -30341,6 +31021,113 @@ "yargs": "^17.6.2" }, "dependencies": { + "@chainsafe/persistent-merkle-tree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", + "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1" + } + }, + "@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==" + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", + "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", + "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==" + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "requires": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", + "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "requires": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "@chainsafe/ssz": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", + "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", + "requires": { + "@chainsafe/as-sha256": "^0.3.1", + "@chainsafe/persistent-merkle-tree": "^0.5.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, "@nomiclabs/hardhat-solhint": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-solhint/-/hardhat-solhint-2.0.1.tgz", @@ -30349,11 +31136,35 @@ "solhint": "^2.0.0" } }, + "@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "requires": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "requires": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, "acorn": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -30526,6 +31337,17 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "requires": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, "file-entry-cache": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", @@ -30534,6 +31356,14 @@ "flat-cache": "^2.0.1" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "requires": { + "locate-path": "^2.0.0" + } + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -30554,6 +31384,63 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, + "hardhat": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", + "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "requires": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.1", + "@nomicfoundation/ethereumjs-blockchain": "7.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.1", + "@nomicfoundation/ethereumjs-evm": "2.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-statemanager": "2.0.1", + "@nomicfoundation/ethereumjs-trie": "6.0.1", + "@nomicfoundation/ethereumjs-tx": "5.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -30578,6 +31465,14 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "requires": { + "graceful-fs": "^4.1.6" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -30587,6 +31482,15 @@ "type-check": "~0.3.2" } }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -30600,6 +31504,22 @@ "word-wrap": "~1.2.3" } }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "requires": { + "p-limit": "^1.1.0" + } + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -30609,6 +31529,11 @@ "json-parse-better-errors": "^1.0.1" } }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" + }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -30666,6 +31591,46 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + } + } + }, "solhint": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/solhint/-/solhint-2.3.1.tgz", @@ -30807,412 +31772,6 @@ "yargs": "^17.7.2" }, "dependencies": { - "@chainsafe/persistent-merkle-tree": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz", - "integrity": "sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw==", - "requires": { - "@chainsafe/as-sha256": "^0.3.1" - } - }, - "@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==" - }, - "@nomicfoundation/ethereumjs-block": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", - "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", - "requires": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-blockchain": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", - "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", - "requires": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-ethash": "3.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "level": "^8.0.0", - "lru-cache": "^5.1.1", - "memory-level": "^1.0.0" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-common": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", - "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", - "requires": { - "@nomicfoundation/ethereumjs-util": "9.0.2", - "crc-32": "^1.2.0" - } - }, - "@nomicfoundation/ethereumjs-ethash": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", - "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", - "requires": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "abstract-level": "^1.0.3", - "bigint-crypto-utils": "^3.0.23", - "ethereum-cryptography": "0.1.3" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-evm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", - "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", - "requires": { - "@ethersproject/providers": "^5.7.1", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", - "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==" - }, - "@nomicfoundation/ethereumjs-statemanager": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", - "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", - "requires": { - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "ethers": "^5.7.1", - "js-sdsl": "^4.1.4" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-trie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", - "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", - "requires": { - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@types/readable-stream": "^2.3.13", - "ethereum-cryptography": "0.1.3", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-tx": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", - "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", - "requires": { - "@chainsafe/ssz": "^0.9.2", - "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "ethereum-cryptography": "0.1.3" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-util": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", - "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", - "requires": { - "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "ethereum-cryptography": "0.1.3" - }, - "dependencies": { - "@chainsafe/ssz": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@chainsafe/ssz/-/ssz-0.10.2.tgz", - "integrity": "sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg==", - "requires": { - "@chainsafe/as-sha256": "^0.3.1", - "@chainsafe/persistent-merkle-tree": "^0.5.0" - } - }, - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@nomicfoundation/ethereumjs-vm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", - "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", - "requires": { - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "debug": "^4.3.3", - "ethereum-cryptography": "0.1.3", - "mcl-wasm": "^0.7.1", - "rustbn.js": "~0.2.0" - }, - "dependencies": { - "ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "requires": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - } - } - }, - "@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "requires": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "requires": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -31243,131 +31802,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "commander": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" - }, - "ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "requires": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "requires": { - "locate-path": "^2.0.0" - } - }, - "hardhat": { - "version": "2.19.4", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.19.4.tgz", - "integrity": "sha512-fTQJpqSt3Xo9Mn/WrdblNGAfcANM6XC3tAEi6YogB4s02DmTf93A8QsGb8uR0KR8TFcpcS8lgiW4ugAIYpnbrQ==", - "requires": { - "@ethersproject/abi": "^5.1.2", - "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.2", - "@nomicfoundation/ethereumjs-blockchain": "7.0.2", - "@nomicfoundation/ethereumjs-common": "4.0.2", - "@nomicfoundation/ethereumjs-evm": "2.0.2", - "@nomicfoundation/ethereumjs-rlp": "5.0.2", - "@nomicfoundation/ethereumjs-statemanager": "2.0.2", - "@nomicfoundation/ethereumjs-trie": "6.0.2", - "@nomicfoundation/ethereumjs-tx": "5.0.2", - "@nomicfoundation/ethereumjs-util": "9.0.2", - "@nomicfoundation/ethereumjs-vm": "7.0.2", - "@nomicfoundation/solidity-analyzer": "^0.1.0", - "@sentry/node": "^5.18.1", - "@types/bn.js": "^5.1.0", - "@types/lru-cache": "^5.1.0", - "adm-zip": "^0.4.16", - "aggregate-error": "^3.0.0", - "ansi-escapes": "^4.3.0", - "chalk": "^2.4.2", - "chokidar": "^3.4.0", - "ci-info": "^2.0.0", - "debug": "^4.1.1", - "enquirer": "^2.3.0", - "env-paths": "^2.2.0", - "ethereum-cryptography": "^1.0.3", - "ethereumjs-abi": "^0.6.8", - "find-up": "^2.1.0", - "fp-ts": "1.19.3", - "fs-extra": "^7.0.1", - "glob": "7.2.0", - "immutable": "^4.0.0-rc.12", - "io-ts": "1.10.4", - "keccak": "^3.0.2", - "lodash": "^4.17.11", - "mnemonist": "^0.38.0", - "mocha": "^10.0.0", - "p-map": "^4.0.0", - "raw-body": "^2.4.1", - "resolve": "1.17.0", - "semver": "^6.3.0", - "solc": "0.7.3", - "source-map-support": "^0.5.13", - "stacktrace-parser": "^0.1.10", - "tsort": "0.0.1", - "undici": "^5.14.0", - "uuid": "^8.3.2", - "ws": "^7.4.6" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "hardhat-deploy": { "version": "0.11.45", "resolved": "https://registry.npmjs.org/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz", @@ -31441,92 +31875,6 @@ "universalify": "^2.0.0" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "requires": { - "p-limit": "^1.1.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - }, - "solc": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", - "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", - "requires": { - "command-exists": "^1.2.8", - "commander": "3.0.2", - "follow-redirects": "^1.12.1", - "fs-extra": "^0.30.0", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "require-from-string": "^2.0.0", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "dependencies": { - "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" - } - }, - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" - } - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -33203,9 +33551,9 @@ "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" }, "abstract-level": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", - "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.4.tgz", + "integrity": "sha512-eUP/6pbXBkMbXFdx4IH2fVgvB7M0JvR7/lIL33zcs0IBcwjdzSSl31TOJsaCzmKSSDF9h8QYSOJux4Nd4YJqFg==", "requires": { "buffer": "^6.0.3", "catering": "^2.1.0", @@ -33335,6 +33683,14 @@ "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "optional": true }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "requires": { + "string-width": "^4.1.0" + } + }, "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -33681,6 +34037,66 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -34092,9 +34508,9 @@ "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==" }, "classic-level": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.3.0.tgz", - "integrity": "sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.4.1.tgz", + "integrity": "sha512-qGx/KJl3bvtOHrGau2WklEZuXhS3zme+jf+fsu6Ej7W7IP/C49v7KNlWIsT1jZu0YnfzSIYDGcEWpCa1wKGWXQ==", "requires": { "abstract-level": "^1.0.2", "catering": "^2.1.0", @@ -34116,6 +34532,11 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -42693,30 +43114,24 @@ } }, "hardhat": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.1.tgz", - "integrity": "sha512-H3Qp/UKyQGmPDDBSfMoSyH18rRnac90rsb0LNer+sKe6at6rxLe4D5j+M+1icqZQF02iLPjNRwc/PA8OPf757A==", + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.2.tgz", + "integrity": "sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw==", "requires": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-blockchain": "7.0.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-evm": "2.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-statemanager": "2.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", - "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", "@types/lru-cache": "^5.1.0", - "abort-controller": "^3.0.0", "adm-zip": "^0.4.16", "aggregate-error": "^3.0.0", "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", "chalk": "^2.4.2", "chokidar": "^3.4.0", "ci-info": "^2.0.0", @@ -42736,7 +43151,6 @@ "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", - "qs": "^6.7.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", @@ -43964,10 +44378,11 @@ } }, "level": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", - "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.1.tgz", + "integrity": "sha512-oPBGkheysuw7DmzFQYyFe8NAia5jFLAgEnkgWnK3OXAuJr8qFT+xBQIwokAZPME2bhPFzS8hlYcL16m8UZrtwQ==", "requires": { + "abstract-level": "^1.0.4", "browser-level": "^1.0.1", "classic-level": "^1.2.0" } @@ -48554,6 +48969,14 @@ } } }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, "window-size": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", diff --git a/package.json b/package.json index 8cb2e45e..8fe5ca43 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "ethereumjs-tx": "^2.1.2", "ethers": "5.7.2", "graphql": "^16.6.0", - "hardhat": "2.14.1", + "hardhat": "2.22.2", "hardhat-abi-exporter": "^2.10.1", "hardhat-change-network": "^0.0.7", "hardhat-contract-sizer": "^2.8.0", diff --git a/scripts/utils/tx-params.ts b/scripts/utils/tx-params.ts index 28e97870..1699a1a6 100644 --- a/scripts/utils/tx-params.ts +++ b/scripts/utils/tx-params.ts @@ -22,7 +22,7 @@ type OWLRACLE_RESPONSE = { export async function txParamsBasic(provider: providers.Provider, hre: HardhatRuntimeEnvironment, acceptance = 2) { const feeData = await provider.getFeeData(); - + // console.log("feeData", feeData); console.log('maxPriorityFeePerGas', formatUnits(feeData.maxPriorityFeePerGas?.toString() ?? '0', 9)); console.log('maxFeePerGas', formatUnits(feeData.maxFeePerGas?.toString() ?? '0', 9)); @@ -54,10 +54,14 @@ export async function txParamsBasic(provider: providers.Provider, hre: HardhatRu maxFeesPerNetwork(hre), ); const maxFeePerGas = (feeData.maxFeePerGas?.toNumber() ?? 1) * 2; - return { - maxPriorityFeePerGas: maxPriorityFeePerGas.toFixed(0), - maxFeePerGas: maxFeePerGas.toFixed(0), + const ret = { + maxPriorityFeePerGas: (1.2*feeData.maxPriorityFeePerGas.toNumber()).toFixed(0), + maxFeePerGas: (1.2*maxFeePerGas).toFixed(0), + // gasPrice: ((feeData.gasPrice?.toNumber() ?? 1) * 1.2).toFixed(0) }; + // console.log("ret", ret); + // console.log("maxFeesPerNetwork(hre)", maxFeesPerNetwork(hre)) + return ret; } else { return { gasPrice: ((feeData.gasPrice?.toNumber() ?? 1) * 1.2).toFixed(0),