Skip to content

Commit c9557bb

Browse files
author
omriss
committed
#431: fix coverage
1 parent db869b2 commit c9557bb

6 files changed

Lines changed: 388 additions & 133 deletions

File tree

src/strategies/AaveLeverageMerklFarmStrategy.sol

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ contract AaveLeverageMerklFarmStrategy is
266266

267267
/// @inheritdoc ILeverageLendingStrategy
268268
function health()
269-
public
269+
external
270270
view
271271
returns (
272272
uint ltv,
@@ -277,7 +277,8 @@ contract AaveLeverageMerklFarmStrategy is
277277
uint targetLeveragePercent
278278
)
279279
{
280-
return ALMFLib.health(platform(), _getLeverageLendingBaseStorage(), _getFarm());
280+
(ltv, maxLtv, leverage, collateralAmount, debtAmount, targetLeveragePercent) =
281+
ALMFLib.health(platform(), _getLeverageLendingBaseStorage(), _getFarm());
281282
}
282283

283284
/// @inheritdoc ILeverageLendingStrategy
@@ -359,7 +360,7 @@ contract AaveLeverageMerklFarmStrategy is
359360
uint[] memory /*amountsConsumed*/
360361
)
361362
{
362-
revert("no underlying"); // todo do we need to support it?
363+
revert("no underlying");
363364
}
364365

365366
/// @inheritdoc StrategyBase
@@ -368,7 +369,7 @@ contract AaveLeverageMerklFarmStrategy is
368369
/*amount*/
369370
address /*receiver*/
370371
) internal pure override {
371-
revert("no underlying"); // todo do we need to support it?
372+
revert("no underlying");
372373
}
373374

374375
/// @inheritdoc IStrategy
@@ -385,13 +386,11 @@ contract AaveLeverageMerklFarmStrategy is
385386
/// @inheritdoc StrategyBase
386387
function _previewDepositAssets(uint[] memory amountsMax)
387388
internal
388-
pure
389+
view
389390
override
390391
returns (uint[] memory amountsConsumed, uint value)
391392
{
392-
amountsConsumed = new uint[](1);
393-
amountsConsumed[0] = amountsMax[0];
394-
value = amountsMax[0]; // todo this value is incorrect
393+
return ALMFLib.previewDepositValue(_getLeverageLendingBaseStorage(), amountsMax);
395394
}
396395

397396
//endregion ----------------------------------- Strategy base

src/strategies/libs/ALMFCalcLib.sol

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,31 @@ library ALMFCalcLib {
171171
return Math.min(amount, optionalLimit);
172172
}
173173

174+
/// @notice Adjust leverage towards target range using leverage coefficient k if necessary: L_adj = L + k (TL - L)
175+
/// @param leverage Current leverage, INTERNAL_PRECISION
176+
/// @param minTargetLeverage Minimum target leverage, INTERNAL_PRECISION
177+
/// @param maxTargetLeverage Maximum target leverage, INTERNAL_PRECISION
178+
/// @param k Coefficient for adjustment [0...INTERNAL_PRECISION)
179+
/// @return leverageAdj Adjusted leverage, INTERNAL_PRECISION
180+
function adjustLeverage(
181+
uint leverage,
182+
uint minTargetLeverage,
183+
uint maxTargetLeverage,
184+
uint k
185+
) internal pure returns (uint leverageAdj) {
186+
// calculate target leverage as average value
187+
uint targetLeverage = (minTargetLeverage + maxTargetLeverage) / 2;
188+
189+
// calculate adjusted leverage
190+
if (leverage < minTargetLeverage) {
191+
leverageAdj = leverage + k * (targetLeverage - leverage) / ALMFCalcLib.INTERNAL_PRECISION;
192+
} else if (leverage > maxTargetLeverage) {
193+
leverageAdj = leverage - k * (leverage - targetLeverage) / ALMFCalcLib.INTERNAL_PRECISION;
194+
} else {
195+
leverageAdj = leverage;
196+
}
197+
}
198+
174199
//endregion ------------------------------------- Withdraw logic
175200

176201
//region ------------------------------------- State

src/strategies/libs/ALMFLib.sol

Lines changed: 35 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ library ALMFLib {
100100
{
101101
address lendingVault = $.lendingVault;
102102
uint collateralAmountTotal = totalCollateral(lendingVault);
103-
// todo emergency? collateralAmountTotal -= collateralAmountTotal / 1000; // todo do we need it?
104103

105104
IPool(IAToken(lendingVault).POOL())
106105
.withdraw(collateralAsset, Math.min(tempCollateralAmount, collateralAmountTotal), address(this));
@@ -174,8 +173,6 @@ library ALMFLib {
174173
}
175174

176175
if ($.tempAction == ILeverageLendingStrategy.CurrentAction.IncreaseLtv) {
177-
uint tempCollateralAmount = $.tempCollateralAmount;
178-
179176
// swap
180177
_swap(
181178
platform,
@@ -188,14 +185,7 @@ library ALMFLib {
188185

189186
// supply
190187
IPool(IAToken($.lendingVault).POOL())
191-
.deposit(
192-
collateralAsset,
193-
ALMFCalcLib.getLimitedAmount(
194-
IERC20(collateralAsset).balanceOf(address(this)), tempCollateralAmount
195-
),
196-
address(this),
197-
0
198-
);
188+
.deposit(collateralAsset, IERC20(collateralAsset).balanceOf(address(this)), address(this), 0);
199189

200190
// borrow
201191
IPool(IAToken($.borrowingVault).POOL())
@@ -210,11 +200,6 @@ library ALMFLib {
210200
IPool(IAToken($.borrowingVault).POOL())
211201
.repay(token, tokenBalance, INTEREST_RATE_MODE_VARIABLE, address(this));
212202
}
213-
214-
// reset temp vars
215-
if (tempCollateralAmount != 0) {
216-
$.tempCollateralAmount = 0;
217-
}
218203
}
219204

220205
// ensure that all rewards are still exist on the balance
@@ -375,7 +360,6 @@ library ALMFLib {
375360
address pool = IAToken(data.borrowingVault).POOL();
376361
uint amountToRepay = StrategyLib.balance(data.borrowAsset) - borrowBalanceBefore;
377362
if (amountToRepay != 0) {
378-
IERC20(data.borrowAsset).forceApprove(pool, amountToRepay);
379363
IPool(pool).repay(data.borrowAsset, amountToRepay, INTEREST_RATE_MODE_VARIABLE, address(this));
380364
}
381365
}
@@ -414,18 +398,6 @@ library ALMFLib {
414398

415399
// assume here that den > 0; it's safer to revert in other case
416400
flashAmount = ALMFCalcLib._baseToBorrow(num / den, data.priceB18, data.decimalsB);
417-
418-
// console.log("_getDepositFlashAmount.targetLeverage", targetLeverage);
419-
// console.log("_getDepositFlashAmount.amountBase", amountBase);
420-
// console.log("_getDepositFlashAmount.den", den);
421-
// console.log("_getDepositFlashAmount.num", num);
422-
// console.log("_getDepositFlashAmount.flashAmount", flashAmount);
423-
// console.log("targetLeverage * (state.collateralBase + amountBase + state.debtBase)", targetLeverage * (state.collateralBase + amountBase - state.debtBase));
424-
// console.log("targetLeverage", targetLeverage);
425-
// console.log("state.collateralBase", state.collateralBase);
426-
// console.log("amountBase", amountBase);
427-
// console.log("state.debtBase", state.debtBase);
428-
// console.log("(state.collateralBase + amountBase) * ALMFCalcLib.INTERNAL_PRECISION", (state.collateralBase + amountBase) * ALMFCalcLib.INTERNAL_PRECISION);
429401
}
430402

431403
//endregion ------------------------------------- Deposit
@@ -456,17 +428,17 @@ library ALMFLib {
456428
}
457429

458430
// ---------------------- Transfer required amount to the user
459-
uint balBase = ALMFCalcLib.collateralToBase(StrategyLib.balance(data.collateralAsset), data);
460-
uint valueNow = balBase + calcTotal(state);
431+
uint balance = StrategyLib.balance(data.collateralAsset);
432+
uint valueNow = ALMFCalcLib.collateralToBase(balance, data) + calcTotal(state);
461433

462434
amountsOut = new uint[](1);
463435
if (valueWas > valueNow) {
464-
amountsOut[0] = ALMFCalcLib.baseToCollateral(Math.min(value - (valueWas - valueNow), balBase), data);
436+
amountsOut[0] = Math.min(ALMFCalcLib.baseToCollateral(value - (valueWas - valueNow), data), balance);
465437
} else {
466-
amountsOut[0] = ALMFCalcLib.baseToCollateral(Math.min(value + (valueNow - valueWas), balBase), data);
438+
amountsOut[0] = Math.min(ALMFCalcLib.baseToCollateral(value + (valueNow - valueWas), data), balance);
467439
}
468440

469-
// todo check amountsOut >= actual balance
441+
// we can have dust amounts of collateral on strategy balance here
470442

471443
if (receiver != address(this)) {
472444
IERC20(data.collateralAsset).safeTransfer(receiver, amountsOut[0]);
@@ -491,10 +463,8 @@ library ALMFLib {
491463
uint collateralBalanceBase = ALMFCalcLib.collateralToBase(balance, data);
492464

493465
// collateral amount required to withdraw from lending pool
494-
uint amountToWithdraw = Math.min(
495-
ALMFCalcLib.baseToCollateral(value > collateralBalanceBase ? value - collateralBalanceBase : 0, data),
496-
balance
497-
);
466+
uint amountToWithdraw =
467+
ALMFCalcLib.baseToCollateral(value > collateralBalanceBase ? value - collateralBalanceBase : 0, data);
498468

499469
if (amountToWithdraw != 0) {
500470
IPool(IAToken(data.lendingVault).POOL()).withdraw(data.collateralAsset, amountToWithdraw, address(this));
@@ -511,17 +481,12 @@ library ALMFLib {
511481
ALMFCalcLib.State memory state,
512482
uint value
513483
) internal {
514-
uint leverage = ALMFCalcLib.getLeverage(state.collateralBase, state.debtBase);
515-
516-
{
517-
// use leverage correction (coefficient k = withdrawParam0) if necessary: L_adj = L + k (TL - L)
518-
uint targetLeverage = (data.minTargetLeverage + data.maxTargetLeverage) / 2;
519-
if (leverage < data.minTargetLeverage) {
520-
leverage = leverage + $.withdrawParam0 * (targetLeverage - leverage) / ALMFCalcLib.INTERNAL_PRECISION;
521-
} else if (leverage > data.maxTargetLeverage) {
522-
leverage = leverage - $.withdrawParam0 * (leverage - targetLeverage) / ALMFCalcLib.INTERNAL_PRECISION;
523-
}
524-
}
484+
uint leverage = ALMFCalcLib.adjustLeverage(
485+
ALMFCalcLib.getLeverage(state.collateralBase, state.debtBase),
486+
data.minTargetLeverage,
487+
data.maxTargetLeverage,
488+
$.withdrawParam0
489+
);
525490

526491
(uint flashAmount, uint collateralToWithdraw) = ALMFCalcLib.calcWithdrawAmounts(value, leverage, data, state);
527492

@@ -535,10 +500,8 @@ library ALMFLib {
535500
// special case: don't use flash, just withdraw required amount from aave and send it to the user
536501
IPool(IAToken(data.lendingVault).POOL()).withdraw(data.collateralAsset, collateralToWithdraw, address(this));
537502
} else {
538-
uint[] memory flashAmounts = new uint[](1);
539-
flashAmounts[0] = flashAmount;
540-
address[] memory flashAssets = new address[](1);
541-
flashAssets[0] = $.borrowAsset;
503+
(address[] memory flashAssets, uint[] memory flashAmounts) =
504+
_getFlashLoanAmounts(flashAmount, data.borrowAsset);
542505

543506
$.tempCollateralAmount = collateralToWithdraw;
544507

@@ -598,19 +561,6 @@ library ALMFLib {
598561

599562
(data.minTargetLeverage, data.maxTargetLeverage) = _getFarmLeverageConfig(farm);
600563

601-
// console.log("collateralAsset", data.collateralAsset);
602-
// console.log("borrowAsset", data.borrowAsset);
603-
// console.log("lendingVault", data.lendingVault);
604-
// console.log("borrowingVault", data.borrowingVault);
605-
//// console.log("flashLoanVault", data.flashLoanVault);
606-
//// console.log("flashLoanKind", data.flashLoanKind);
607-
// console.log("swapFee18", data.swapFee18);
608-
// console.log("flashFee18", data.flashFee18);
609-
// console.log("priceC18", data.priceC18);
610-
// console.log("priceB18", data.priceB18);
611-
// console.log("minTargetLeverage", data.minTargetLeverage);
612-
// console.log("maxTargetLeverage", data.maxTargetLeverage);
613-
614564
return data;
615565
}
616566

@@ -633,12 +583,6 @@ library ALMFLib {
633583
maxLtv: maxLtv,
634584
healthFactor: healthFactor
635585
});
636-
637-
// console.log("collateralBase", state.collateralBase);
638-
// console.log("debtBase", state.debtBase);
639-
// console.log("maxLtv", state.maxLtv);
640-
// console.log("healthFactor", state.healthFactor);
641-
// console.log("current ltv", ALMFCalcLib.getLtv(state.collateralBase, state.debtBase));
642586
}
643587

644588
/// @notice Get current state: collateral and debt in base asset (USD, 18 decimals)
@@ -650,6 +594,7 @@ library ALMFLib {
650594
return IAToken(lendingVault).balanceOf(address(this));
651595
}
652596

597+
/// @dev not optimal by gas, but it's ok for view function
653598
function health(
654599
address platform,
655600
ILeverageLendingStrategy.LeverageLendingBaseStorage storage $,
@@ -666,7 +611,7 @@ library ALMFLib {
666611
uint targetLeveragePercent
667612
)
668613
{
669-
ALMFCalcLib.StaticData memory data = _getStaticData(platform, $, farm); // todo it can be optimized
614+
ALMFCalcLib.StaticData memory data = _getStaticData(platform, $, farm);
670615
IPool pool = IPool(IAToken(data.lendingVault).POOL());
671616

672617
// Maximum LTV with 4 decimals
@@ -702,6 +647,23 @@ library ALMFLib {
702647
totalValue = calcTotal(_getState(IAToken($.lendingVault).POOL()));
703648
}
704649

650+
function previewDepositValue(
651+
ILeverageLendingStrategy.LeverageLendingBaseStorage storage $,
652+
uint[] memory amountsMax
653+
) external view returns (uint[] memory amountsConsumed, uint value) {
654+
amountsConsumed = new uint[](1);
655+
amountsConsumed[0] = amountsMax[0];
656+
657+
address collateralAsset = $.collateralAsset;
658+
659+
// value is [total collateral - total debt] in USD, 18 decimals
660+
uint price8 = IAavePriceOracle(
661+
IAaveAddressProvider(IPool(IAToken($.lendingVault).POOL()).ADDRESSES_PROVIDER()).getPriceOracle()
662+
).getAssetPrice(collateralAsset);
663+
664+
value = amountsMax[0] * price8 * 1e10 / (10 ** IERC20Metadata(collateralAsset).decimals());
665+
}
666+
705667
//endregion ------------------------------------- View
706668

707669
//region ------------------------------------- Swap

0 commit comments

Comments
 (0)