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: 73/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
https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L617
When yieldFeeRecipient calls the claimYieldFeeShares() function with an amount of shares that is less than the yieldFeeBalance, the yieldFeeBalance will be reset to 0. As a result, the difference between the claimed shares and the yieldFeeBalance will effectively be lost.
Here is a coded POC which can be directly pasted in Liquidate.t.sol
import {console2} from "forge-std/Test.sol";
function testClaimYieldFeeShares_withdrawPartial() 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 yieldFeeBalanceBefore = vault.yieldFeeBalance(); console2.log("YieldFeeBalance before claim: ", yieldFeeBalanceBefore); // YieldFeeBalance before claim: 99999999999900000 vm.prank(bob); vault.claimYieldFeeShares(yieldFeeBalanceBefore / 3); console2.log("Balance of Bob after claim: ", vault.balanceOf(bob)); // Balance of Bob after claim: 33333333333300000 uint256 yieldFeeBalanceAfter = vault.yieldFeeBalance(); console2.log("YieldFeeBalance after claim: ", yieldFeeBalanceAfter); // YieldFeeBalance after claim: 0 // The yieldFeeBalanceAfter is 0 after the claim, but should be 66666666666600000 (yieldFeeBalanceBefore - yieldFeeBalanceBefore / 3) }
Manual Analysis
The error is caused from a logical error inside the claimYieldFeeShares() here is the suggested patch to fix this error in PrizeVault.sol:
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); }
Other
#0 - c4-pre-sort
2024-03-11T21:41:40Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:41:45Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:15Z
raymondfam marked the issue as duplicate of #59
#3 - c4-judge
2024-03-15T07:40:27Z
hansfriese marked the issue as satisfactory