Platform: Code4rena
Start Date: 31/01/2023
Pot Size: $90,500 USDC
Total HM: 47
Participants: 169
Period: 7 days
Judge: LSDan
Total Solo HM: 9
Id: 211
League: ETH
Rank: 90/169
Findings: 1
Award: $69.38
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: immeas
Also found by: KIntern_NA, bin2chen, minhtrng, rbserver, rvierdiiev, ustas, yellowBirdy
69.3758 USDC - $69.38
https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L496-L499 https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L134-L140 https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L170-L176 https://github.com/code-423n4/2023-01-popcorn/blob/main/src/vault/Vault.sol#L170-L176
Accrued performance fees are calculated of the difference between current value and the value recorded in highWaterMark
.
DEPOSIT, MINT and WITHDRAW use syncFeeCheckpoint
modifier which updates highWaterMark
to current share value.
If one of the above functions is called when there are any not yet taken performance fees they will be reset to 0 by virtue of setting highWaterMark
to current share value.
As users will DEPOSIT, MINT and WITHDRAW possibly significantly more often than fees being taken most of the performance fees will be lost to the vault creator.
It also be used to front run the takeManagementAndPerformanceFees
calls.
Take the following test case where a deposit is performed after fee accrual event but before fee being taken.
function test__performanceFeeDisapearing() public { uint128 amount = 315576000; uint256 depositAmount = 1 ether; _setFees(0, 0, 0, 1e17); asset.mint(alice, depositAmount * 2); vm.startPrank(alice); asset.approve(address(vault), depositAmount); vault.deposit(depositAmount, alice); vm.stopPrank(); // Increase asset assets to trigger performanceFee asset.mint(address(adapter), amount); uint256 expectedFeeInAsseBefore = vault.accruedPerformanceFee(); vm.startPrank(alice); asset.approve(address(vault), depositAmount); vault.deposit(depositAmount, alice); vm.stopPrank(); uint256 expectedFeeInAssetAfter = vault.accruedPerformanceFee(); assertEq(expectedFeeInAssetAfter, expectedFeeInAsseBefore); }
it will with the following error:
Error: a == b not satisfied [uint] Expected: 31557600 Actual: 0
Forge
I can see two possible solutions:
I'm leaning towards the first as a more elegant one, keeping the separation of concerns between adapter and vault intact.
#0 - c4-judge
2023-02-16T06:10:09Z
dmvt marked the issue as primary issue
#1 - c4-sponsor
2023-02-17T09:39:59Z
RedVeil marked the issue as sponsor confirmed
#2 - c4-judge
2023-02-23T00:12:29Z
dmvt marked the issue as satisfactory
#3 - c4-judge
2023-02-23T01:20:54Z
dmvt marked issue #780 as primary and marked this issue as a duplicate of 780