Trick or Treat

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

Improving Randomness

Summary

The current implementation of randomness in the SpookySwap contract uses a pseudo-random number generator based on keccak256 and block.timestamp, which is vulnerable to miner manipulation. This allows for the possibility of unfair outcomes in the trick-or-treat process

Vulnerability Details

In the trickOrTreat function, randomness is generated using the following code:

solidity

uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, nextTokenId, block.prevrandao))) % 1000 + 1;

This method of generating randomness is not secure. Miners can manipulate the block timestamp or choose whether or not to include certain transactions based on favorable outcomes, especially given the 1/1000 chance for the "trick" (double price) and "treat" (half price).

Impact

The manipulation of randomness could lead to the following:

  • Users obtaining an unfair advantage in the minting process, receiving a treat (half-price mint) more frequently.

  • Exploiting the "trick" scenario by intentionally delaying transactions or controlling the outcome, resulting in financial losses for other users and unfair pricing.

  • This could erode trust in the platform's fairness, particularly if malicious actors exploit these vulnerabilities.

Tools Used

  • Manual Code Review: A thorough review of the smart contract identified the use of insecure pseudo-randomness.

    • Solidity Security Best Practices: Cross-checked against industry standards for secure randomness.

Recommendations

To securely generate randomness and prevent manipulation, it is recommended to integrate Chainlink VRF. This provides a cryptographically secure and provable source of randomness.
```

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract SpookySwap is ERC721URIStorage, Ownable(msg.sender), ReentrancyGuard, VRFConsumerBase {
// Add necessary Chainlink VRF variables
bytes32 internal keyHash;
uint256 internal fee;
constructor(Treat[] memory treats)
ERC721("SpookyTreats", "SPKY")
VRFConsumerBase(VRFCoordinator, LINKToken)
{
keyHash = /* keyHash from Chainlink */;
fee = /* Chainlink fee */;
nextTokenId = 1;
for (uint256 i = 0; i < treats.length; i++) {
addTreat(treats[i].name, treats[i].cost, treats[i].metadataURI);
}
}
function requestRandomnessForTreat() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK to pay fee");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
uint256 random = randomness % 1000 + 1;
// Use this random value in the trick-or-treat logic
}
}

}
```

Updates

Appeal created

bube Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

[invalid] Weak randomness

It's written in the README: "We're aware of the pseudorandom nature of the current implementation. This will be replaced with Chainlink VRF in later builds." This is a known issue.

Support

FAQs

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