Trick or Treat

First Flight #27
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Invalid

Incorrect Discount logic in trickOrTreat Function Results in Overcharging Users

A flaw has been identified in the trickOrTreat function within the smart contract, specifically in the implementation of the half-price discount mechanism for NFT minting. Users eligible for this discount cannot utilize it properly, which may result in unintended overcharges, affecting user satisfaction and platform trust.

Issue Description

The trickOrTreat function utilizes a pseudo-random number generator to determine pricing adjustments for treats, including a potential half-price discount. However, the current logic does not correctly apply the discount when the random number matches the condition for a half-price offer. As a result, users may be charged the full price even when a discount is due, or face confusion regarding the actual payment required. This could lead to overpayment or missed discounts, adversely affecting the user experience.

Code Snippet

function trickOrTreat(string memory _treatName) public payable nonReentrant {
Treat memory treat = treatList[_treatName];
require(treat.cost > 0, "Treat cost not set.");
uint256 costMultiplierNumerator = 1;
uint256 costMultiplierDenominator = 1;
// Generate a pseudo-random number between 1 and 1000
uint256 random =
uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, nextTokenId, block.prevrandao))) % 1000 + 1;
if (random == 1) {
// 1/1000 chance of half price (treat) - e.g., 1/2 -> 0.5
costMultiplierNumerator = 1;
costMultiplierDenominator = 2;
} else if (random == 2) {
// 1/1000 chance of double price (trick) - e.g., 2/1 -> 2.0
costMultiplierNumerator = 2;
costMultiplierDenominator = 1;
}
uint256 requiredCost = (treat.cost * costMultiplierNumerator) / costMultiplierDenominator;
// Incorrect handling of the half-price scenario
if (costMultiplierNumerator == 2 && costMultiplierDenominator == 1) {
if (msg.value >= requiredCost) {
mintTreat(msg.sender, treat);
} else {
// Store the pending purchase
}
} else {
require(msg.value >= requiredCost, "Insufficient ETH sent for treat");
mintTreat(msg.sender, treat);
}
// Refund excess ETH if any.
if (msg.value > requiredCost) {
uint256 refund = msg.value - requiredCost;
(bool refundSuccess,) = msg.sender.call{value: refund}("");
require(refundSuccess, "Refund failed");
}
}

Impact

The issue leads to:

  • Financial Discrepancies: Users who qualify for the half-price discount (1/2 multiplier) are not able to receive the discounted rate. This could cause financial losses and potential dissatisfaction among users.

  • Reduced Trust in Platform: The random reward mechanism is inconsistent, leading to a perception of unfairness and potentially damaging the reputation of the platform.

Tools Used

Manual Code Analysis

Recommendation

To address this issue, update the function logic to properly handle the half-price scenario. Ensure that users who receive a 1/2 cost multiplier are charged the appropriate discounted amount.

Suggested Code Fix

if (costMultiplierNumerator == 2 && costMultiplierDenominator == 1) {
// Double price scenario
require(msg.value >= requiredCost, "Insufficient ETH sent for treat");
mintTreat(msg.sender, treat);
} else if (costMultiplierNumerator == 1 && costMultiplierDenominator == 2) {
// Half price scenario
require(msg.value >= requiredCost, "Insufficient ETH sent for treat");
mintTreat(msg.sender, treat);
} else {
// Default case
require(msg.value >= requiredCost, "Insufficient ETH sent for treat");
mintTreat(msg.sender, treat);
}

This modification ensures that each price adjustment scenario is handled correctly, allowing users to benefit from the intended discounts or price increases.

Updates

Appeal created

bube Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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