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: 61/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
There is a logical error in the claimYieldFeeShares
function of the PrizeVault
contract.
function claimYieldFeeShares(uint256 _shares) external onlyYieldFeeRecipient { if (_shares == 0) revert MintZeroShares(); uint256 _yieldFeeBalance = yieldFeeBalance; if (_shares > _yieldFeeBalance) revert SharesExceedsYieldFeeBalance(_shares, _yieldFeeBalance); yieldFeeBalance -= _yieldFeeBalance; _mint(msg.sender, _shares); emit ClaimYieldFeeShares(msg.sender, _shares); }
This line yieldFeeBalance -= _yieldFeeBalance;
is intended to subtract the amount of yield fee shares (_shares
) being claimed from the yieldFeeBalance
, which tracks the total amount of shares that have been accrued as fees and are claimable by the yieldFeeRecipient
.
However, instead of subtracting the shares being claimed (_shares
), the current balance itself (_yieldFeeBalance
) is being subtracted from yieldFeeBalance
. This would incorrectly reduce the yieldFeeBalance
to zero regardless of the amount of shares actually claimed, which is not the intended behavior.
function testClaimYieldFeeShares_withdrawPartialBalance() 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(); console2.log("Before claiming, yieldFeeBalance = %d", yieldFeeBalance); assertGt(yieldFeeBalance, 0); vm.startPrank(bob); vm.expectEmit(); emit Transfer(address(0), bob, yieldFeeBalance / 3); vm.expectEmit(); emit ClaimYieldFeeShares(bob, yieldFeeBalance / 3); console2.log("Claim one third of all yield fees with shares: %d", yieldFeeBalance / 3); vault.claimYieldFeeShares(yieldFeeBalance / 3); vm.stopPrank(); assertEq(vault.balanceOf(bob), yieldFeeBalance / 3); yieldFeeBalance = vault.yieldFeeBalance(); console2.log("After claiming, yieldFeeBalance = %d", yieldFeeBalance); }
Test output:
$ forge test --mt testClaimYieldFeeShares_withdrawPartialBalance -vv [â ’] Compiling... [â ‘] Compiling 1 files with 0.8.24 [â ˜] Solc 0.8.24 finished in 15.08s Compiler run successful! Ran 1 test for test/unit/PrizeVault/Liquidate.t.sol:PrizeVaultLiquidationTest [PASS] testClaimYieldFeeShares_withdrawPartialBalance() (gas: 319613) Logs: Before claiming, yieldFeeBalance = 99999999999900000 Claim one third of all yield fees with shares: 33333333333300000 After claiming, yieldFeeBalance = 0 Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.93ms
Foundry, VSCode
The correct implementation should be:
yieldFeeBalance -= _shares;
Other
#0 - c4-pre-sort
2024-03-11T21:40:53Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:40:58Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:13Z
raymondfam marked the issue as duplicate of #59
#3 - c4-judge
2024-03-15T07:37:30Z
hansfriese changed the severity to 3 (High Risk)
#4 - c4-judge
2024-03-15T07:40:33Z
hansfriese marked the issue as satisfactory