Platform: Code4rena
Start Date: 04/03/2024
Pot Size: $36,500 USDC
Total HM: 9
Participants: 80
Period: 7 days
Judge: hansfriese
Total Solo HM: 2
Id: 332
League: ETH
Rank: 65/80
Findings: 1
Award: $1.47
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: DarkTower
Also found by: 0xJaeger, 0xJoyBoy03, 0xRiO, 0xkeesmark, 0xlemon, 0xmystery, Abdessamed, AcT3R, Afriauditor, AgileJune, Al-Qa-qa, Aymen0909, Daniel526, DanielTan_MetaTrust, Dots, FastChecker, Fitro, GoSlang, Greed, Krace, McToady, SoosheeTheWise, Tripathi, asui, aua_oo7, btk, crypticdefense, d3e4, dd0x7e8, dvrkzy, gesha17, iberry, kR1s, leegh, marqymarq10, n1punp, pa6kuda, radin100, sammy, smbv-1923, trachev, turvy_fuzz, valentin_s2304, wangxx2026, y4y, yotov721, yvuchev, zhaojie
1.4652 USDC - $1.47
The protocol provides the ability to set yield fee and yield fee recipient when registering an Yield Vault in the Prize Vault Factory. The yield fee is accumulated when a user decides to transfer tokens out of the contract as seen in PrizeVault::transferTokensOut
... uint32 _yieldFeePercentage = yieldFeePercentage; // Determine the proportional yield fee based on the amount being liquidated: uint256 _yieldFee; if (_yieldFeePercentage != 0) { // The yield fee is calculated as a portion of the total yield being consumed, such that // `total = amountOut + yieldFee` and `yieldFee / total = yieldFeePercentage`. @ _yieldFee = (_amountOut * FEE_PRECISION) / (FEE_PRECISION - _yieldFeePercentage) - _amountOut; } // Ensure total liquidation amount does not exceed the available yield balance: if (_amountOut + _yieldFee > _availableYield) { revert LiquidationExceedsAvailable(_amountOut + _yieldFee, _availableYield); } // Increase yield fee balance: if (_yieldFee > 0) { @ yieldFeeBalance += _yieldFee; } ...
The accumulated yield can then be withdrawn by the yield fee recipient via PrizeVault::claimYieldFeeShares
. The function takes in one parameter specifying the amount of accumulated yield shares to mint.
However instead of subtracting the amount of shares from the yield fee balance, the balance is subtracted from itself, effectively setting it to zero loosing the yildFeeBalance - _shares
amount.
Note that this issue is not present if _shares
== _yieldFeeBalance
.
Add the following test to Liquidate.t.sol
and run with forge test --mt testClaimYieldFeeShares_YieldDeleted -vvv
function testClaimYieldFeeShares_YieldDeleted() public { vault.setYieldFeePercentage(1e8); // 10% fee vault.setYieldFeeRecipient(bob); vault.setLiquidationPair(address(this)); // liquidate some yield underlyingAsset.mint(address(vault), 1e18); uint256 amountOut = vault.liquidatableBalanceOf(address(underlyingAsset)); assertGt(amountOut, 0); vault.transferTokensOut(address(0), alice, address(underlyingAsset), amountOut); uint256 yieldFeeBalance = vault.yieldFeeBalance(); console.log("yieldFeeBalance before: ", yieldFeeBalance); vm.prank(bob); vault.claimYieldFeeShares(yieldFeeBalance / 3); assertEq(vault.balanceOf(bob), yieldFeeBalance / 3); console.log("yieldFeeBalance after: ", vault.yieldFeeBalance()); console.log("Yieeld Fee Bob balance: ", vault.balanceOf(bob)); }
Manual Review, Foundry
function claimYieldFeeShares(uint256 _shares) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; if (_shares > _yieldFeeBalance) revert SharesExceedsYieldFeeBalance(_shares, _yieldFeeBalance); - yieldFeeBalance -= _yieldFeeBalance; + yieldFeeBalance -= _shares; _mint(msg.sender, _shares); emit ClaimYieldFeeShares(msg.sender, _shares); }
Math
#0 - c4-pre-sort
2024-03-11T21:52:19Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:52:24Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:29Z
raymondfam marked the issue as duplicate of #59
#3 - c4-judge
2024-03-15T07:39:05Z
hansfriese marked the issue as satisfactory