Trick or Treat

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

Constructor allows duplicate treat names

Summary

The SpookySwap contract's constructor allows duplicate treat names to be added during initialization, potentially leading to data inconsistency and unexpected behavior in the treat management system.

Vulnerability Details

The contract initializes treats in the constructor without checking for duplicates:

constructor(Treat[] memory treats) ERC721("SpookyTreats", "SPKY") {
nextTokenId = 1;
// @audit no check for duplicates
for (uint256 i = 0; i < treats.length; i++) {
addTreat(treats[i].name, treats[i].cost, treats[i].metadataURI);
}
}

The issue extends to the addTreat function which is called by the constructor:

function addTreat(string memory _name, uint256 _rate, string memory _metadataURI) public onlyOwner {
treatList[_name] = Treat(_name, _rate, _metadataURI);
treatNames.push(_name);
emit TreatAdded(_name, _rate, _metadataURI);
}

Example of problematic initialization:

Treat[] memory treats = new Treat[]();
treats[0] = Treat("Candy", 1 ether, "uri1");
treats[1] = Treat("Chocolate", 2 ether, "uri2");
treats[2] = Treat("Candy", 3 ether, "uri3"); // Duplicate name
SpookySwap spooky = new SpookySwap(treats);

This leads to:

  1. The treatList mapping will only store the last entry for "Candy"

  2. The treatNames array will contain duplicate entries

  3. Original cost and URI information for the first "Candy" entry will be lost

Impact

  • Data inconsistency between treatList and treatNames

  • Misleading enumeration of available treats

  • Potential confusion for users and front-end applications

  • Incorrect statistics about the number of unique treats

Tools Used

  • Manual review

Recommendations

  1. Add duplicate check in constructor:

constructor(Treat[] memory treats) ERC721("SpookyTreats", "SPKY") {
nextTokenId = 1;
// Track used names
mapping(string => bool) storage usedNames;
for (uint256 i = 0; i < treats.length; i++) {
require(!usedNames[treats[i].name], "Duplicate treat name");
usedNames[treats[i].name] = true;
addTreat(treats[i].name, treats[i].cost, treats[i].metadataURI);
}
}
Updates

Appeal created

bube Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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