function buyPass(uint256 collectionId) external payable {
require(passSupply[collectionId] < passMaxSupply[collectionId], "Max supply reached");
_mint(msg.sender, collectionId, 1, "");
++passSupply[collectionId];
}
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";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
contract BuyPassTest is Test {
FestivalPass public festivalPass;
BeatToken public beatToken;
Alice public alice;
function setUp() public {
beatToken = new BeatToken();
festivalPass = new FestivalPass(address(beatToken), address(this));
alice = new Alice();
}
function test_buyPass() public {
uint maxSupply = 10;
festivalPass.configurePass(1, 1 ether, maxSupply);
festivalPass.configurePass(2, 2 ether, maxSupply);
festivalPass.configurePass(3, 3 ether, maxSupply);
vm.deal(address(alice), 100 ether);
alice.buyPass(festivalPass, 1);
assertGt(festivalPass.balanceOf(address(alice), 1), maxSupply);
}
}
contract Alice {
uint buyPassCount;
FestivalPass festivalPass;
function buyPass(FestivalPass _festivalPass, uint256 collectionId) public {
festivalPass = _festivalPass;
festivalPass.buyPass{value: 1 ether}(collectionId);
}
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) public returns (bytes4) {
buyPassCount++;
if (buyPassCount < 20) {
this.buyPass(festivalPass, id);
}
buyPassCount = 0;
festivalPass = FestivalPass(address(0));
return IERC1155Receiver.onERC1155Received.selector;
}
}
function buyPass(uint256 collectionId) external payable {
require(collectionId == GENERAL_PASS || collectionId == VIP_PASS || collectionId == BACKSTAGE_PASS, "Invalid pass ID");
require(msg.value == passPrice[collectionId], "Incorrect payment amount");
require(passSupply[collectionId] < passMaxSupply[collectionId], "Max supply reached");
+ // Update state before external call
+ ++passSupply[collectionId];
// Mint 1 pass to buyer
_mint(msg.sender, collectionId, 1, "");
- ++passSupply[collectionId];
// VIP gets 5 BEAT welcome bonus BACKSTAGE gets 15 BEAT welcome bonus
uint256 bonus = (collectionId == VIP_PASS) ? 5e18 : (collectionId == BACKSTAGE_PASS) ? 15e18 : 0;
if (bonus > 0) {
BeatToken(beatToken).mint(msg.sender, bonus);
}
emit PassPurchased(msg.sender, collectionId);
}