function getMultiplier(address user) public view returns (uint256) {
if (balanceOf(user, BACKSTAGE_PASS) > 0) {
return 3;
} else if (balanceOf(user, VIP_PASS) > 0) {
return 2;
} else if (balanceOf(user, GENERAL_PASS) > 0) {
return 1;
}
return 0;
}
For example, once a user owns just 1 backstage pass, they permanently receive the 3x multiplier for all future performances, regardless of how many other passes they own or how many times they attend performances.
Users can game the system by purchasing just one backstage pass to unlock permanent 3x multipliers
function test_MultiplierBugVulnerability() public {
uint256 baseReward = 100e18;
vm.startPrank(organizer);
uint256 performanceId1 = festivalPass.createPerformance(
block.timestamp + 1 hours,
10 hours,
baseReward
);
uint256 performanceId2 = festivalPass.createPerformance(
block.timestamp + 1 hours,
10 hours,
baseReward
);
uint256 performanceId3 = festivalPass.createPerformance(
block.timestamp + 1 hours,
10 hours,
baseReward
);
vm.stopPrank();
vm.startPrank(user1);
festivalPass.buyPass{value: GENERAL_PRICE}(1);
festivalPass.buyPass{value: GENERAL_PRICE}(1);
festivalPass.buyPass{value: BACKSTAGE_PRICE}(3);
vm.stopPrank();
uint256 multiplier = festivalPass.getMultiplier(user1);
assertEq(multiplier, 3, "User gets 3x multiplier with just 1 backstage pass");
vm.warp(block.timestamp + 1 hours + 30 minutes);
vm.startPrank(user1);
festivalPass.attendPerformance(performanceId1);
vm.warp(block.timestamp + COOLDOWN);
festivalPass.attendPerformance(performanceId2);
vm.warp(block.timestamp + COOLDOWN);
festivalPass.attendPerformance(performanceId3);
vm.stopPrank();
uint256 actualPerformanceReward = baseReward * 3 * 3;
uint256 actualTotal = BACKSTAGE_WELCOME_BONUS + actualPerformanceReward;
assertEq(beatToken.balanceOf(user1), actualTotal);
uint256 fairPerformanceReward = (1 * baseReward) + (1 * baseReward) + (3 * baseReward);
uint256 fairTotal = BACKSTAGE_WELCOME_BONUS + fairPerformanceReward;
assertGt(actualTotal, fairTotal);
}