From 199ca1781a5c372144d905f3f56fcee0cf593590 Mon Sep 17 00:00:00 2001 From: Haythem Sellami <17862704+haythemsellami@users.noreply.github.com> Date: Fri, 14 Jun 2024 08:45:28 +0300 Subject: [PATCH 1/4] accrue performance fee in underlying asset --- src/FourSixTwoSixAgg.sol | 24 ++++++++++++++++-------- test/e2e/PerformanceFeeE2ETest.t.sol | 3 +-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/FourSixTwoSixAgg.sol b/src/FourSixTwoSixAgg.sol index daff6e86..12e09ab8 100644 --- a/src/FourSixTwoSixAgg.sol +++ b/src/FourSixTwoSixAgg.sol @@ -104,7 +104,7 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 event ReorderWithdrawalQueue(uint8 index1, uint8 index2); event AddStrategy(address indexed strategy, uint256 allocationPoints); event RemoveStrategy(address indexed _strategy); - event AccruePerformanceFee(address indexed feeRecipient, uint256 performanceFee, uint256 yield, uint256 feeShares); + event AccruePerformanceFee(address indexed feeRecipient, uint256 yield, uint256 feeAssets); event SetStrategyCap(address indexed strategy, uint256 cap); event Rebalance(address indexed strategy, uint256 _amountToRebalance, bool _isDeposit); @@ -609,10 +609,15 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 } else if (underlyingBalance > strategyAllocatedAmount) { // There's yield! uint256 yield = underlyingBalance - strategyAllocatedAmount; + uint120 accruedPerformanceFee = _accruePerformanceFee(_strategy, yield); + + if (accruedPerformanceFee != 0) { + underlyingBalance -= accruedPerformanceFee; + yield -= accruedPerformanceFee; + } + strategies[_strategy].allocated = uint120(underlyingBalance); totalAllocated += yield; - - _accruePerformanceFee(yield); } else { uint256 loss = strategyAllocatedAmount - underlyingBalance; @@ -632,19 +637,22 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 emit Harvest(_strategy, underlyingBalance, strategyAllocatedAmount); } - function _accruePerformanceFee(uint256 _yield) internal { + function _accruePerformanceFee(address _strategy, uint256 _yield) internal returns (uint120) { address cachedFeeRecipient = feeRecipient; uint256 cachedPerformanceFee = performanceFee; - if (cachedFeeRecipient == address(0) || cachedPerformanceFee == 0) return; + if (cachedFeeRecipient == address(0) || cachedPerformanceFee == 0) return 0; // `feeAssets` will be rounded down to 0 if `yield * performanceFee < 1e18`. uint256 feeAssets = Math.mulDiv(_yield, cachedPerformanceFee, 1e18, Math.Rounding.Down); - uint256 feeShares = _convertToShares(feeAssets, Math.Rounding.Down); - if (feeShares != 0) _mint(cachedFeeRecipient, feeShares); + if(feeAssets > 0) { + IERC4626(_strategy).withdraw(feeAssets, cachedFeeRecipient, address(this)); + } + + emit AccruePerformanceFee(cachedFeeRecipient, _yield, feeAssets); - emit AccruePerformanceFee(cachedFeeRecipient, cachedPerformanceFee, _yield, feeShares); + return feeAssets.toUint120(); } /// @dev Override _afterTokenTransfer hook to call IBalanceTracker.balanceTrackerHook() diff --git a/test/e2e/PerformanceFeeE2ETest.t.sol b/test/e2e/PerformanceFeeE2ETest.t.sol index f8cec8a9..81652b74 100644 --- a/test/e2e/PerformanceFeeE2ETest.t.sol +++ b/test/e2e/PerformanceFeeE2ETest.t.sol @@ -102,13 +102,12 @@ contract PerformanceFeeE2ETest is FourSixTwoSixAggBase { } uint256 expectedPerformanceFee = yield * fourSixTwoSixAgg.performanceFee() / 1e18; - uint256 expectedPerformanceFeeShares = fourSixTwoSixAgg.convertToShares(expectedPerformanceFee); // harvest vm.prank(user1); fourSixTwoSixAgg.harvest(address(eTST)); - assertEq(fourSixTwoSixAgg.balanceOf(feeRecipient), expectedPerformanceFeeShares); + assertEq(assetTST.balanceOf(feeRecipient), expectedPerformanceFee); // full withdraw, will have to withdraw from strategy as cash reserve is not enough { From d1329a3c31e61b3471a414751755cb6234099a64 Mon Sep 17 00:00:00 2001 From: Haythem Sellami <17862704+haythemsellami@users.noreply.github.com> Date: Fri, 14 Jun 2024 08:46:58 +0300 Subject: [PATCH 2/4] lint --- src/FourSixTwoSixAgg.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FourSixTwoSixAgg.sol b/src/FourSixTwoSixAgg.sol index 12e09ab8..074c0f15 100644 --- a/src/FourSixTwoSixAgg.sol +++ b/src/FourSixTwoSixAgg.sol @@ -615,7 +615,7 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 underlyingBalance -= accruedPerformanceFee; yield -= accruedPerformanceFee; } - + strategies[_strategy].allocated = uint120(underlyingBalance); totalAllocated += yield; } else { @@ -646,9 +646,9 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 // `feeAssets` will be rounded down to 0 if `yield * performanceFee < 1e18`. uint256 feeAssets = Math.mulDiv(_yield, cachedPerformanceFee, 1e18, Math.Rounding.Down); - if(feeAssets > 0) { + if (feeAssets > 0) { IERC4626(_strategy).withdraw(feeAssets, cachedFeeRecipient, address(this)); - } + } emit AccruePerformanceFee(cachedFeeRecipient, _yield, feeAssets); From 42832adc4fc8c34ca9dae120fa794ab775c8e597 Mon Sep 17 00:00:00 2001 From: Haythem Sellami <17862704+haythemsellami@users.noreply.github.com> Date: Fri, 14 Jun 2024 08:49:15 +0300 Subject: [PATCH 3/4] use > instead of != --- src/FourSixTwoSixAgg.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FourSixTwoSixAgg.sol b/src/FourSixTwoSixAgg.sol index 074c0f15..adc22130 100644 --- a/src/FourSixTwoSixAgg.sol +++ b/src/FourSixTwoSixAgg.sol @@ -611,7 +611,7 @@ contract FourSixTwoSixAgg is IFourSixTwoSixAgg, BalanceForwarder, EVCUtil, ERC46 uint256 yield = underlyingBalance - strategyAllocatedAmount; uint120 accruedPerformanceFee = _accruePerformanceFee(_strategy, yield); - if (accruedPerformanceFee != 0) { + if (accruedPerformanceFee > 0) { underlyingBalance -= accruedPerformanceFee; yield -= accruedPerformanceFee; } From 82d34311ab0f6b658067b7b607ddc6dbdacc5fe0 Mon Sep 17 00:00:00 2001 From: Haythem Sellami <17862704+haythemsellami@users.noreply.github.com> Date: Fri, 14 Jun 2024 08:53:43 +0300 Subject: [PATCH 4/4] test: add asserts --- test/e2e/PerformanceFeeE2ETest.t.sol | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/e2e/PerformanceFeeE2ETest.t.sol b/test/e2e/PerformanceFeeE2ETest.t.sol index 81652b74..f72e6eb8 100644 --- a/test/e2e/PerformanceFeeE2ETest.t.sol +++ b/test/e2e/PerformanceFeeE2ETest.t.sol @@ -103,11 +103,19 @@ contract PerformanceFeeE2ETest is FourSixTwoSixAggBase { uint256 expectedPerformanceFee = yield * fourSixTwoSixAgg.performanceFee() / 1e18; + FourSixTwoSixAgg.Strategy memory strategyBeforeHarvest = fourSixTwoSixAgg.getStrategy(address(eTST)); + uint256 totalAllocatedBefore = fourSixTwoSixAgg.totalAllocated(); + // harvest vm.prank(user1); fourSixTwoSixAgg.harvest(address(eTST)); assertEq(assetTST.balanceOf(feeRecipient), expectedPerformanceFee); + assertEq( + fourSixTwoSixAgg.getStrategy(address(eTST)).allocated, + strategyBeforeHarvest.allocated + yield - expectedPerformanceFee + ); + assertEq(fourSixTwoSixAgg.totalAllocated(), totalAllocatedBefore + yield - expectedPerformanceFee); // full withdraw, will have to withdraw from strategy as cash reserve is not enough {