Summary
The claimAllRewards() function appears to be vulnerable to reentrancy attacks.
Vulnerability Details
function claimAllRewards() public {
uint256 totalValue = 0;
for (uint256 i = 0; i < rewardsOwned[msg.sender].length; i++) {
totalValue += rewardsOwned[msg.sender][i].value;
}
require(totalValue > 0, "No rewards to claim");
(bool success,) = payable(msg.sender).call{value: totalValue}("");
require(success, "Transfer failed");
delete rewardsOwned[msg.sender];
}
Impact
if the recipient of the funds (msg.sender) is another smart contract, it could potentially execute code during the transfer, leading to unexpected behavior, for example claim all rewards
Tools Used
Aderyn + Foundry
Recommendations
use OpenZeppelin's SafeERC20 library along with the checkEffectsBeforeEvents pattern and emit RewardClaimed after deletion instead of previous approach
import "@openzeppelin/contracts/token/ERC20/extensions/draft/SafeERC20.sol";
using SafeERC20 for IERC20;
function claimAllRewards() public {
uint256 totalValue = 0;
for (uint256 i = 0; i < rewardsOwned[msg.sender].length; i++) {
totalValue += rewardsOwned[msg.sender][i].value;
}
require(totalValue > 0, "No rewards to claim");
// Transfer all rewards to the user
+ for (uint256 i = 0; i < rewardsOwned[msg.sender].length; i++) {
+ IERC20(rewardsOwned[msg.sender][i].token).safeTransfer(msg.sender, rewardsOwned[msg.sender][i].value);
+ }
delete rewardsOwned[msg.sender];
+ emit RewardsClaimed(msg.sender, totalValue);
}