The totalFees variable is declared as uint64, which maxes out at approximately 18.4 ETH. In selectWinner(), the fee is calculated as a uint256 and then unsafely downcast to uint64. Since the contract runs on Solidity 0.7.6, which has no built-in overflow protection, the value silently wraps around when it exceeds the uint64 maximum. The protocol permanently loses track of its fees.
Likelihood:
This triggers every time cumulative fees cross the ~18.4 ETH boundary
For a popular raffle with a reasonable entrance fee, this threshold is reached quickly
Impact:
Protocol fees silently reset to an incorrect random value
The withdrawFees() strict equality check (address(this).balance == uint256(totalFees)) will also mismatch, potentially locking all fees permanently
Direct revenue loss for the protocol with no recovery path
This test demonstrates the overflow in a concrete scenario. Assume entranceFee is 1 ETH and 100 players enter the raffle. The total collected is 100 ETH, and the 20% fee is 20 ETH. When selectWinner() executes totalFees = totalFees + uint64(fee), the 20 ETH value (20,000,000,000,000,000,000 wei) exceeds the uint64 maximum. On Solidity 0.7.6, this silently wraps around to a small garbage value instead of reverting. The owner then calls withdrawFees(), but it reverts because address(this).balance no longer equals uint256(totalFees). The fees are permanently locked in the contract with no recovery mechanism.
Change totalFees from uint64 to uint256 so it matches the precision of the fee calculation. The uint64 type can only hold ~18.4 ETH which is an unreasonably low ceiling for a protocol collecting fees. With uint256, overflow is practically impossible (the max value is larger than the total ETH supply many times over). Alternatively, upgrading to Solidity 0.8.x would add automatic overflow checks that revert the transaction instead of wrapping silently, but changing the type is the cleaner fix since it addresses the root cause rather than just catching the symptom.
## Description ## Vulnerability Details The type conversion from uint256 to uint64 in the expression 'totalFees = totalFees + uint64(fee)' may potentially cause overflow problems if the 'fee' exceeds the maximum value that a uint64 can accommodate (2^64 - 1). ```javascript totalFees = totalFees + uint64(fee); ``` ## POC <details> <summary>Code</summary> ```javascript function testOverflow() public { uint256 initialBalance = address(puppyRaffle).balance; // This value is greater than the maximum value a uint64 can hold uint256 fee = 2**64; // Send ether to the contract (bool success, ) = address(puppyRaffle).call{value: fee}(""); assertTrue(success); uint256 finalBalance = address(puppyRaffle).balance; // Check if the contract's balance increased by the expected amount assertEq(finalBalance, initialBalance + fee); } ``` </details> In this test, assertTrue(success) checks if the ether was successfully sent to the contract, and assertEq(finalBalance, initialBalance + fee) checks if the contract's balance increased by the expected amount. If the balance didn't increase as expected, it could indicate an overflow. ## Impact This could consequently lead to inaccuracies in the computation of 'totalFees'. ## Recommendations To resolve this issue, you should change the data type of `totalFees` from `uint64` to `uint256`. This will prevent any potential overflow issues, as `uint256` can accommodate much larger numbers than `uint64`. Here's how you can do it: Change the declaration of `totalFees` from: ```javascript uint64 public totalFees = 0; ``` to: ```jasvascript uint256 public totalFees = 0; ``` And update the line where `totalFees` is updated from: ```diff - totalFees = totalFees + uint64(fee); + totalFees = totalFees + fee; ``` This way, you ensure that the data types are consistent and can handle the range of values that your contract may encounter.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.