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: 75/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
claimYieldFeeShares()
is used for the collection of yield fees to a specific recipient.
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); }
As observed, _shares
is used to specify the amount of fees to collect, the issue arises when _shares != yieldFeeBalance
. The issue lies in the fact that only _shares
are minted, but the entire yieldFeeBalance
is subtracted. Consequently, the remaining fees are lost, specifically yieldFeeBalance - _shares
.
To execute the POC copy the provided code into the PrizeVault.t.sol
file.
function testYieldFeeLost() public { vault.setYieldFeePercentage(1e8); // 10% vault.setYieldFeeRecipient(bob); assertEq(vault.totalDebt(), 0); // 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; uint256 yieldFee = (1e18 - vault.yieldBuffer()) / (2 * 10); // 10% yield fee + 90% amountOut = 100% vault.transferTokensOut(address(0), bob, address(underlyingAsset), amountOut); 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 + yieldFee); // debt increased since we reserved shares for the yield fee vm.startPrank(bob); vault.claimYieldFeeShares(yieldFee / 2); //claim yieldFee / 2 assertEq(vault.totalDebt(), vault.totalSupply()); assertEq(vault.yieldFeeBalance(), 0); //the other yieldFee / 2 is lost vm.stopPrank(); }
As observed, only half of the fees are claimed, but the vault.yieldFeeBalance()
is 0.
Manual review.
Change yieldFeeBalance -= _yieldFeeBalance
for yieldFeeBalance -= _shares
.
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:43:27Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-03-11T21:43:33Z
raymondfam marked the issue as duplicate of #10
#2 - c4-pre-sort
2024-03-13T04:38:17Z
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:20Z
hansfriese marked the issue as satisfactory