Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Integer Overflow/ Underflow in `selectWinner` Function could lead to incorrect fee and prize pool calculations

Summary

The selectWinner function in the PuppyRaffle contract could potentially be vulnerable to arithmetic issues, specifically integer overflow and underflow. This could lead to incorrect fee and prize pool calculations, affecting the contract's precision and accuracy, and potentially locking the funds in the contract.

Vulnerability Details

The selectWinner function calculates the prizePool and fee based on the totalAmountCollected. However, these calculations do not check for potential integer overflow or underflow. If totalAmountCollected is a large value, an integer overflow can occur, leading to incorrect fee and prize pool calculations.

The lines of code that could potentially overflow or underflow are:

uint256 totalAmountCollected = players.length entranceFee;
totalFees = totalFees + uint64(fee);

Also adding uint256 and a uint64 value together can potentially lead to a loss of precision and truncation of data.

  • In the context of the totalFees variable in the PuppyRaffle contract, adding uint256 and uint64 values together may result in the loss of the higher-order bits of the totalFees value.

If the fee value is larger than what can be represented by a uint64, the addition operation will truncate the higher-order bits of the fee value, potentially leading to an inaccurate representation of the total fees.

PoC

Consider a scenario where the players.length is a large value, causing totalAmountCollected to exceed the maximum value representable by uint256:

address[] memory players = new address[](hugeValue);
// Populate players with unique addresses
raffle.enterRaffle(players);
raffle.selectWinner(); // This could potentially cause an integer overflow in the fee and prize pool calculations

In this scenario espacially using solc v.0.7.6 that doesnt automatically solve arithmatic issues, the calculation (totalAmountCollected * 80) / 100 and (totalAmountCollected * 20) / 100 could result in an integer overflow, leading to incorrect prizePool and fee values.

truncation

-lets make it that the initial value of totalFees is 100 and fee is 2**64 (a value larger than what can be represented by uint64), let's calculate the result:

totalFees = 100;
uint256 fee = 2**64;
totalFees = totalFees + uint64(fee);
totalFees = 100 + 0 = 100

Impact

Arithmetic issues can lead to incorrect calculations of the fee and prize pool. This could disrupt the operation of the raffle, leading to potential loss of funds and loss of trust in the contract. It could also affect the contract's precision and accuracy, leading to unfair distribution of prizes and fees.

Moreover, if there is an arithmetic issue such as an integer overflow or underflow, it could potentially cause the check require(address(this).balance == uint256(totalFees), "PuppyRaffle: There are currently players active!"); to always fail. This is because the totalFees variable could become a value that is not representative of the actual total fees due to the arithmetic issue. If totalFees is larger than the actual balance of the contract (due to an overflow), or if it becomes a negative number (due to an underflow), the require statement will always fail and revert the transaction. This would indeed prevent the owner from withdrawing the fees, effectively locking the funds in the contract. This could disrupt the operation of the contract and potentially lead to a loss of trust in the contract.

Tools Used

-Foundry

Recommendations

To mitigate this vulnerability, use the SafeMath library for all arithmetic operations to prevent integer overflows and underflows. Here is an example of how this can be implemented:

import "@openzeppelin/contracts/math/SafeMath.sol";
using SafeMath for uint256;
function selectWinner() public {
uint256 totalAmountCollected = players.length.mul(entranceFee);
uint256 prizePool = totalAmountCollected.mul(80).div(100);
uint256 fee = totalAmountCollected.mul(20).div(100);
// rest of the function logic
}

To avoid potential truncation issues when adding a uint256 and a uint64 value together, you can modify the code as follows:

totalFees = totalFees + fee;

By removing the cast to uint64 and directly adding the fee value to totalFees, you ensure that the addition operation is performed using the same data type (uint256). This eliminates the potential truncation that could occur when using a smaller data type (uint64) for the addition.

This will ensure that all arithmetic operations are safe and prevent potential integer overflows and underflows.

Updates

Lead Judging Commences

Hamiltonite Lead Judge about 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

overflow-uint64

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!