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: 60/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
Yield fee amounts may not be fully collected by the recipient and missed out forever, especially in the case of the yield fee accrual between the transaction submission and tx execution.
The yield fee recipient can claim the accrued yield fee through claimYieldFeeShares
function by specifying how many shares to claim. However, the function will clear all the yield fees, even when the specified shares
is less than the accrued yield fee. This means that the supposedly remaining fee will be gone forever and can no longer be claimed (see the line of code: https://github.com/code-423n4/2024-03-pooltogether/blob/main/pt-v5-vault/src/PrizeVault.sol#L617 )
function claimYieldFeeShares(uint256 _shares) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; if (_shares > _yieldFeeBalance) revert SharesExceedsYieldFeeBalance(_shares, _yieldFeeBalance); yieldFeeBalance -= _yieldFeeBalance; // this actually resets the yield fee balance to 0, even if the _shares is much less _mint(msg.sender, _shares); emit ClaimYieldFeeShares(msg.sender, _shares); }
Under normal circumstances, this may seem to be acceptable.
However, it is possible that there is a frontrunning yield fee accrual that happens before the yield fee claiming (the frontrunning yield fee accrual can happen upon liquidation event). If this happens, then the fee will be total discarded and can never be claimed since the increased yieldFeeBalance
will be reset to 0 according to the problematic line.
Manual Review
Only subtract the yieldFeeBalance
by the minted _shares
instead, for correct accounting, as follows:
function claimYieldFeeShares(uint256 _shares) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; if (_shares > _yieldFeeBalance) revert SharesExceedsYieldFeeBalance(_shares, _yieldFeeBalance); yieldFeeBalance -= _shares; // update this to reduce only by _shares _mint(msg.sender, _shares); emit ClaimYieldFeeShares(msg.sender, _shares); }
Other
#0 - c4-pre-sort
2024-03-11T21:39:01Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:39:07Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:09Z
raymondfam marked the issue as duplicate of #59
#3 - c4-judge
2024-03-15T07:37:31Z
hansfriese changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-15T07:40:39Z
hansfriese marked the issue as satisfactory