@@ -124,10 +124,6 @@ library SiloAdvancedLib {
124124 collateralAmountTotal -= collateralAmountTotal / 1000 ;
125125 ISilo (lendingVault).withdraw (
126126 Math.min (tempCollateralAmount, collateralAmountTotal),
127- // todo
128- // _estimateCollateralAmountToRepay(
129- // platform, collateralAmountTotal, collateralAsset, token, tempCollateralAmount
130- // ),
131127 address (this ),
132128 address (this ),
133129 ISilo.CollateralType.Collateral
@@ -139,10 +135,14 @@ library SiloAdvancedLib {
139135 platform,
140136 collateralAsset,
141137 token,
142- Math.min (tempCollateralAmount, StrategyLib.balance (collateralAsset)),
138+ _estimateSwapAmount (platform, amount + feeAmount, collateralAsset, token, swapPriceImpactTolerance0),
139+ // Math.min(tempCollateralAmount, StrategyLib.balance(collateralAsset)),
143140 swapPriceImpactTolerance0
144141 );
145142
143+ // explicit error for the case when _estimateSwapAmount gives incorrect amount
144+ require (IERC20 (token).balanceOf (address (this )) >= amount + feeAmount, IControllable.InsufficientBalance ());
145+
146146 // pay flash loan
147147 IERC20 (token).safeTransfer (flashLoanVault, amount + feeAmount);
148148
@@ -492,8 +492,12 @@ library SiloAdvancedLib {
492492 );
493493
494494 IVaultMainV3 (payable (vault)).unlock (data);
495- } else if (flashLoanKind == ILeverageLendingStrategy.FlashLoanKind.UniswapV3_2) {
496- // ensure that the vault has available amount
495+ } else if (
496+ // assume here that Algebra uses exactly same API as UniswapV3
497+ flashLoanKind == ILeverageLendingStrategy.FlashLoanKind.UniswapV3_2
498+ || flashLoanKind == ILeverageLendingStrategy.FlashLoanKind.AlgebraV4_3
499+ ) {
500+ // ensure that the pool has available amount
497501 require (
498502 IERC20 (flashAssets[0 ]).balanceOf (address (vault)) >= flashAmounts[0 ], IControllable.InsufficientBalance ()
499503 );
@@ -511,26 +515,31 @@ library SiloAdvancedLib {
511515 }
512516 }
513517
514- function _estimateCollateralAmountToRepay (
518+ /// @notice Estimate amount of collateral to swap to receive {amountToRepay} on balance
519+ /// @param priceImpactTolerance Price impact tolerance. Must include fees at least. Denominator is 100_000.
520+ function _estimateSwapAmount (
515521 address platform ,
516522 uint amountToRepay ,
517523 address collateralAsset ,
518524 address token ,
519- uint tempCollateralAmount
525+ uint priceImpactTolerance
520526 ) internal view returns (uint ) {
521527 // We have collateral C = C1 + C2 where C1 is amount to withdraw, C2 is amount to swap to B (to repay)
522528 // We don't need to swap whole C, we can swap only C2 with same addon (i.e. 10%) for safety
523529
524530 ISwapper swapper = ISwapper (IPlatform (platform).swapper ());
531+ uint requiredAmount = amountToRepay - IERC20 (token).balanceOf (address (this ));
525532
526- // 10% for price impact and slippage
527- uint minCollateralToSwap = swapper.getPrice (token, collateralAsset, amountToRepay) * 110 / 100 ;
533+ // we use higher (x2) price impact then required for safety
534+ uint minCollateralToSwap =
535+ swapper.getPrice (token, collateralAsset, requiredAmount * (100_000 + 2 * priceImpactTolerance) / 100_000 ); // priceImpactTolerance has its own denominator
528536
529- return Math.min (minCollateralToSwap, Math. min (tempCollateralAmount, StrategyLib.balance (collateralAsset) ));
537+ return Math.min (minCollateralToSwap, StrategyLib.balance (collateralAsset));
530538 }
531539
532540 //region ------------------------------------- Deposit
533541 function depositAssets (
542+ address platform ,
534543 ILeverageLendingStrategy.LeverageLendingBaseStorage storage $,
535544 IStrategy.StrategyBaseStorage storage $base,
536545 uint amount ,
@@ -549,6 +558,10 @@ library SiloAdvancedLib {
549558 }
550559
551560 $base.total += value;
561+
562+ // ensure that result LTV doesn't exceed max
563+ (uint maxLtv ,,) = getLtvData (v.lendingVault, $.targetLeveragePercent);
564+ _ensureLtvValid ($, platform, maxLtv);
552565 }
553566
554567 function _deposit (
@@ -574,7 +587,9 @@ library SiloAdvancedLib {
574587
575588 return amountToDeposit * priceCtoB * (10 ** IERC20Metadata (v.borrowAsset).decimals ())
576589 * (targetLeverage - INTERNAL_PRECISION) / INTERNAL_PRECISION / 1e18 // priceCtoB has decimals 1e18
577- / (10 ** IERC20Metadata (v.collateralAsset).decimals ());
590+ // depositParam0 is used to move result leverage to targetValue.
591+ // Otherwise result leverage is higher the target value because of swap losses
592+ * $.depositParam0 / INTERNAL_PRECISION / (10 ** IERC20Metadata (v.collateralAsset).decimals ());
578593 // not sure that its right way, but its working
579594 // flashAmounts[0] = flashAmounts[0] * $.depositParam0 / INTERNAL_PRECISION;
580595 }
@@ -628,6 +643,9 @@ library SiloAdvancedLib {
628643 SiloAdvancedLib._deposit ($, v, Math.min (state.withdrawParam1 * value / INTERNAL_PRECISION, balance));
629644 }
630645 }
646+
647+ // ensure that result LTV doesn't exceed max
648+ _ensureLtvValid ($, platform, state.maxLtv);
631649 }
632650
633651 function withdrawFromLendingVault (
@@ -681,10 +699,6 @@ library SiloAdvancedLib {
681699 _withdrawReduceLeverage ($, v, state, valueToWithdraw);
682700 }
683701 }
684-
685- // ensure that result LTV doesn't exceed max
686- (uint ltv ,,,,,) = health (platform, $);
687- require (ltv <= state.maxLtv, IControllable.IncorrectLtv (ltv));
688702 }
689703
690704 function _withdrawReduceLeverage (
@@ -808,6 +822,17 @@ library SiloAdvancedLib {
808822 //endregion ------------------------------------- Withdraw
809823
810824 //region ------------------------------------- Internal
825+
826+ /// @notice ensure that result LTV doesn't exceed max
827+ function _ensureLtvValid (
828+ ILeverageLendingStrategy.LeverageLendingBaseStorage storage $,
829+ address platform ,
830+ uint maxLtv
831+ ) internal view {
832+ (uint ltv ,,,,,) = health (platform, $);
833+ require (ltv <= maxLtv, IControllable.IncorrectLtv (ltv));
834+ }
835+
811836 function _getFlashLoanAmounts (
812837 uint borrowAmount ,
813838 address borrowAsset
0 commit comments