Beatland Festival

AI First Flight #4
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

`createPerformance()` allows zero reward — attendees burn cooldown for nothing

Description

Root + Impact

  • The createPerformance() function validates that startTime is in the future and duration > 0, but does not validate that reward > 0.

  • An organizer can create a performance with reward = 0. Users who attend this performance consume their 1-hour cooldown (lastCheckIn is updated) but receive 0 BEAT tokens. They are then blocked from attending a legitimate, rewarding performance until the cooldown expires.

function createPerformance(
uint256 startTime,
uint256 duration,
uint256 reward // @> No validation — can be 0
) external onlyOrganizer returns (uint256) {
require(startTime > block.timestamp, "Start time must be in the future");
require(duration > 0, "Duration must be greater than 0");
performances[performanceCount] = Performance({
startTime: startTime,
endTime: startTime + duration,
baseReward: reward // @> Stored as 0 — attendees get nothing
});

Risk

Likelihood:

  • Requires organizer to set reward = 0 (likely a mistake rather than intentional attack)

  • Low probability but easily preventable

Impact:

  • Users waste their cooldown period attending a zero-reward performance

  • Users miss out on concurrent legitimate performances during the wasted cooldown window


Proof of Concept

function test_ZeroRewardPerformance() public {
vm.prank(user1);
festivalPass.buyPass{value: GENERAL_PRICE}(1);
// Organizer creates zero-reward performance
vm.prank(organizer);
uint256 perfId = festivalPass.createPerformance(block.timestamp + 1 hours, 2 hours, 0);
vm.warp(block.timestamp + 90 minutes);
vm.prank(user1);
festivalPass.attendPerformance(perfId);
// User got 0 BEAT but cooldown is consumed
assertEq(beatToken.balanceOf(user1), 0);
assertEq(festivalPass.lastCheckIn(user1), block.timestamp);
console.log("User earned 0 BEAT but cooldown is now active for 1 hour");
}

Recommended Mitigation

function createPerformance(
uint256 startTime,
uint256 duration,
uint256 reward
) external onlyOrganizer returns (uint256) {
require(startTime > block.timestamp, "Start time must be in the future");
require(duration > 0, "Duration must be greater than 0");
+ require(reward > 0, "Reward must be greater than 0");
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 2 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!