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: 74/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 claimYieldFeeShares()
function in PrizeVault.sol
takes an input of uint256 _shares
, which is the number of shares the yield fee recipient wishes to claim. However, while calculating the new value of the yieldFeeBalance
, the function decrements it by _yieldFeeBalance
(equal to yieldFeeBalance
), effectively setting it to zero, irrespective of the value of _shares
that the yield fee recipient inputs in the function call.
The yield fee recipient loses the remainder of their claimable balance (yieldFeeBalance - _shares
) as yieldFeeBalance
is set to zero.
The following Proof of Code has been written assuming a scenario wherein the yieldFeeRecipent
claims half of the accrued yieldFeeBalance
.
To run the test:
PrizeVault.t.sol
file.function testPoc() external{ // set up the yield fee recipent and the yield fee percentage vault.setYieldFeePercentage(1e8); // 10% vault.setYieldFeeRecipient(bob); // make an initial deposit underlyingAsset.mint(alice, 1e18); vm.startPrank(alice); underlyingAsset.approve(address(vault), 1e18); vault.deposit(1e18, alice); vm.stopPrank(); assertEq(vault.totalAssets(), 1e18); assertEq(vault.totalSupply(), 1e18); assertEq(vault.totalDebt(), 1e18); // mint yield to the vault and liquidate underlyingAsset.mint(address(vault), 1e18); vault.setLiquidationPair(address(this)); uint256 maxLiquidation = vault.liquidatableBalanceOf(address(underlyingAsset)); uint256 amountOut = maxLiquidation / 2; vault.transferTokensOut(address(0), bob, address(underlyingAsset), amountOut); uint256 yieldFeeBalance = vault.yieldFeeBalance(); assertEq(vault.totalAssets(), 1e18 + 1e18 - amountOut); // existing balance + yield - amountOut assertEq(vault.totalSupply(), 1e18); // no change in supply since liquidation was for assets assertEq(vault.totalDebt(), 1e18 + yieldFeeBalance); // debt increased since we reserved shares for the yield fee vm.startPrank(bob); // the recipent claims half the yieldFeeBalance vault.claimYieldFeeShares(yieldFeeBalance/2); // however, the remaining yieldFeeBalance is not the expected amount assertNotEq(vault.yieldFeeBalance(), yieldFeeBalance/2); // the recipent loses their entire balance, as it is now 0 assertEq(vault.yieldFeeBalance(), 0); vm.stopPrank(); }
forge test --match-test testPoc
Output :
Ran 1 test for test/unit/PrizeVault/PrizeVault.t.sol:PrizeVaultTest [PASS] testPoc() (gas: 509919) Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 3.16ms (754.40ยตs CPU time) Ran 1 test suite in 115.40ms (3.16ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Foundry
Make the following change to the claimYieldFeeShares()
function in PrizeVault.sol
:
- yieldFeeBalance -= _yieldFeeBalance; + yieldFeeBalance -= _shares;
Error
#0 - c4-pre-sort
2024-03-11T21:43:57Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:44:02Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:18Z
raymondfam marked the issue as duplicate of #59
#3 - c4-judge
2024-03-15T07:40:16Z
hansfriese marked the issue as satisfactory