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

Due to rounding error in calculation of payout fees ether can get stuck in the contract.

[L-1] Due to rounding error in calculation of payout fees in Dussehra::killRavana, payout to the organiser and winner can be incomplete, resulting in ether being accumulated in the contract without a means to retrieve it.

Description: Due to rounding error in calculation of payout fees in Dussehra::killRavana, payout to the organiser and winner can be incomplete, resulting in ether being accumulated in the contract without a means to retrieve it. This will occur when the entree fee ends with an odd number and an odd number of participants have entered.

totalAmountGivenToRam = (totalAmountByThePeople * 50) / 100;

Impact: There is a chance that the contract will not payout in full.

Proof of Concept:

  1. The organiser sets the fee to an odd number (for instance 1 ether + 1);

  2. An odd number of participants enters the protocol.

  3. Ravana is killed, and fees are collected.

  4. The balance of the Dussehra is not zero.

Proof of Concept

Place the following in Dussehra.t.sol.

function test_roundingErrorLeavesFundsInContract() public {
// we start by setting up a dussehra contract with a fee that has value behind the comma.
uint256 entreeFee = 1 ether + 1;
vm.startPrank(organiser);
Dussehra dussehraRoundingError = new Dussehra(entreeFee, address(choosingRam), address(ramNFT));
vm.stopPrank();
vm.startPrank(player1);
vm.deal(player1, entreeFee);
dussehraRoundingError.enterPeopleWhoLikeRam{value: entreeFee}();
vm.stopPrank();
vm.startPrank(player2);
vm.deal(player2, entreeFee);
dussehraRoundingError.enterPeopleWhoLikeRam{value: entreeFee}();
vm.stopPrank();
vm.startPrank(player3);
vm.deal(player3, entreeFee);
dussehraRoundingError.enterPeopleWhoLikeRam{value: entreeFee}();
vm.stopPrank();
// the organiser first has to select Ram..
vm.warp(1728691200 + 1);
vm.startPrank(organiser);
choosingRam.selectRamIfNotSelected();
vm.stopPrank();
// we call the killRavana function
vm.warp(1728691069 + 1);
vm.startPrank(player4);
dussehraRoundingError.killRavana();
vm.stopPrank();
// and we call the withdraw function
address selectedRam = choosingRam.selectedRam();
vm.startPrank(selectedRam);
dussehraRoundingError.withdraw();
vm.stopPrank();
// there are funds left in the contract, meanwhile `totalAmountGivenToRam` has been reset to 0.
// the discrepancy means that the difference will never be retrievable.
assert(address(dussehraRoundingError).balance != 0);
assert(dussehraRoundingError.totalAmountGivenToRam() == 0);
}

Recommended Mitigation: The simplest mitigation is to always set the entree fee to a even number, such as 1 ether.

Updates

Lead Judging Commences

bube Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Dust

Support

FAQs

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