withdrawProtocolFees() Possible malicious or accidental withdrawal of all rewards
criticalLines of code
Vulnerability details
Impact
claimReward() will take all rewards if the amountRequested passed in is 0, which may result in user's rewards lost
Proof of Concept
In BoostAggregator.withdrawProtocolFees(), the owner can take the protocol rewards protocolRewards
The code is as follows:
solidityfunction withdrawProtocolFees(address to) external onlyOwner { uniswapV3Staker.claimReward(to, protocolRewards); @> delete protocolRewards; }
From the above code we can see that uniswapV3Staker is called to fetch and then clear protocolRewards
Let's look at the implementation of uniswapV3Staker.claimReward().
soliditycontract UniswapV3Staker is IUniswapV3Staker, Multicallable { .... function claimReward(address to, uint256 amountRequested) external returns (uint256 reward) { reward = rewards[msg.sender]; @> if (amountRequested != 0 && amountRequested < reward) { reward = amountRequested; rewards[msg.sender] -= reward; } else { rewards[msg.sender] = 0; } if (reward > 0) hermes.safeTransfer(to, reward); emit RewardClaimed(to, reward); }
The current implementation is that if the amountRequested==0 passed in means that all rewards[msg.sender] of this msg.sender are taken
This leads to problems.
- If a malicious
ownercallswithdrawProtocolFees()twice in a row, it will definitely take all therewardsof theBoostAggregator. - probably didn't realize that
withdrawProtocolFees()was called whenprotocolRewards==0
As a result, the rewards that belong to users in BoostAggregator are lost
Tools Used
Recommended Mitigation Steps
Modify claimReward() to remove amountRequested != 0
soliditycontract UniswapV3Staker is IUniswapV3Staker, Multicallable { .... function claimReward(address to, uint256 amountRequested) external returns (uint256 reward) { reward = rewards[msg.sender]; - if (amountRequested != 0 && amountRequested < reward) { + if (amountRequested < reward) { reward = amountRequested; rewards[msg.sender] -= reward; } else { rewards[msg.sender] = 0; } if (reward > 0) hermes.safeTransfer(to, reward); emit RewardClaimed(to, reward); }
Assessed type
Context
