Beatland Festival

First Flight #44
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Missing error checks for BeatToken calls can break the contract state


Description

  • Normally, when the contract gives or burns BEAT tokens, it should check if the operation worked.

  • The problem is the contract does not check if BeatToken's mint() or burnFrom() functions succeed. If these fail, the contract still updates its state and emits events, so the real token balances and the contract's records can get out of sync.

// This can fail silently and break the contract state
function buyPass(uint256 collectionId) external payable {
// ...
_mint(msg.sender, collectionId, 1, "");
++passSupply[collectionId];
BeatToken(beatToken).mint(msg.sender, bonus); // @> No check if this worked
emit PassPurchased(msg.sender, collectionId);
}

Risk

Likelihood:

  • This will happen if BeatToken's mint() or burnFrom() fails for any reason (like paused contract, not enough allowance, or a bug).

  • The contract will not notice and will keep going as if everything worked.

Impact:

  • Users may not get their BEAT tokens or may not have tokens burned, but the contract will say they did.

  • The contract's state and the real token balances will not match, which can cause confusion and loss of trust.

Proof of Concept

// If BeatToken.mint() fails or returns false:
function buyPass(uint256 collectionId) external payable {
// ...
_mint(msg.sender, collectionId, 1, "");
++passSupply[collectionId];
BeatToken(beatToken).mint(msg.sender, bonus); // Could fail
emit PassPurchased(msg.sender, collectionId);
// User has pass but no bonus tokens, state is inconsistent
}

Recommended Mitigation

// Add return value checks for all BeatToken operations
- if (bonus > 0) {
- BeatToken(beatToken).mint(msg.sender, bonus);
- }
+ if (bonus > 0) {
+ require(BeatToken(beatToken).mint(msg.sender, bonus), "Failed to mint bonus tokens");
+ }
- require(BeatToken(beatToken).burnFrom(msg.sender, collection.priceInBeat));
+ require(BeatToken(beatToken).burnFrom(msg.sender, collection.priceInBeat), "Failed to burn BEAT tokens");
- require(BeatToken(beatToken).mint(msg.sender, performances[performanceId].baseReward * multiplier));
+ require(BeatToken(beatToken).mint(msg.sender, performances[performanceId].baseReward * multiplier), "Failed to mint reward tokens");

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 month ago
inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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