|
|
|
@ -7,11 +7,15 @@ import {Unaboomer} from "../src/Unaboomer.sol";
|
|
|
|
|
import {Mailbomb} from "../src/Mailbomb.sol";
|
|
|
|
|
|
|
|
|
|
contract UnaboomerTest is Test {
|
|
|
|
|
using stdStorage for StdStorage;
|
|
|
|
|
|
|
|
|
|
Main public main;
|
|
|
|
|
Unaboomer public boomr;
|
|
|
|
|
Mailbomb public bomb;
|
|
|
|
|
uint256 unaboomerPrice;
|
|
|
|
|
uint256 bombPrice;
|
|
|
|
|
address victim = address(1);
|
|
|
|
|
address killer = address(2);
|
|
|
|
|
|
|
|
|
|
function setUp() public {
|
|
|
|
|
main = new Main();
|
|
|
|
@ -42,8 +46,6 @@ contract UnaboomerTest is Test {
|
|
|
|
|
|
|
|
|
|
// ensure killing increments leaderboard
|
|
|
|
|
function testLeaderboard() public {
|
|
|
|
|
address victim = address(1);
|
|
|
|
|
address killer = address(2);
|
|
|
|
|
uint256 amt = 20;
|
|
|
|
|
hoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice * amt}(amt);
|
|
|
|
@ -60,21 +62,112 @@ contract UnaboomerTest is Test {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure killing toggles URI
|
|
|
|
|
function testURIToggling() public {
|
|
|
|
|
boomr.setAliveURI('ipfs://alive/');
|
|
|
|
|
boomr.setDeadURI('ipfs://dead/');
|
|
|
|
|
startHoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice * 1}(1);
|
|
|
|
|
assertEq(boomr.tokenURI(1), 'ipfs://alive/1.json');
|
|
|
|
|
main.sendBombs(1);
|
|
|
|
|
assertEq(boomr.tokenURI(1), 'ipfs://dead/1.json');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure sending bombs burns bombs
|
|
|
|
|
function testBombBurning() public {
|
|
|
|
|
hoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice * 20}(20);
|
|
|
|
|
startHoax(killer);
|
|
|
|
|
main.assembleBombs{value: bombPrice * 20}(20);
|
|
|
|
|
assertEq(main.bombBalance(killer), 20);
|
|
|
|
|
assertEq(main.bombsExploded(), 0);
|
|
|
|
|
main.sendBombs(5);
|
|
|
|
|
assertEq(main.bombBalance(killer), 15);
|
|
|
|
|
assertEq(main.bombsExploded(), 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure supply limits enforced
|
|
|
|
|
// ensure survivor limit enforced
|
|
|
|
|
// ensure only owners can withdraw funds
|
|
|
|
|
// ensure withdraw function actuall works
|
|
|
|
|
|
|
|
|
|
function testMaximumSupply() public {
|
|
|
|
|
uint256 maxSupply = main.unaboomerMaxSupply();
|
|
|
|
|
uint256 slot = stdstore
|
|
|
|
|
.target(address(boomr))
|
|
|
|
|
.sig("minted()")
|
|
|
|
|
.find();
|
|
|
|
|
bytes32 loc = bytes32(slot);
|
|
|
|
|
bytes32 mockedCurrentTokenId = bytes32(abi.encode(maxSupply - 1));
|
|
|
|
|
vm.store(address(boomr), loc, mockedCurrentTokenId);
|
|
|
|
|
assertEq(main.unaboomerSupply(), (maxSupply - 1));
|
|
|
|
|
startHoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice}(1);
|
|
|
|
|
vm.expectRevert(bytes("supply reached"));
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice}(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure survivor limit enforced and actions halted
|
|
|
|
|
function testSurvivors() public {
|
|
|
|
|
uint256 maxSupply = main.unaboomerMaxSupply();
|
|
|
|
|
uint256 maxSurvivorCount = main.unaboomerMaxSurvivorCount();
|
|
|
|
|
uint256 slot = stdstore
|
|
|
|
|
.target(address(boomr))
|
|
|
|
|
.sig("minted()")
|
|
|
|
|
.find();
|
|
|
|
|
bytes32 loc = bytes32(slot);
|
|
|
|
|
bytes32 a = bytes32(abi.encode(maxSupply)); // 10k
|
|
|
|
|
vm.store(address(boomr), loc, a);
|
|
|
|
|
slot = stdstore
|
|
|
|
|
.target(address(boomr))
|
|
|
|
|
.sig("totalKillCount()")
|
|
|
|
|
.find();
|
|
|
|
|
loc = bytes32(slot);
|
|
|
|
|
a = bytes32(abi.encode((maxSupply - maxSurvivorCount))); // 1k
|
|
|
|
|
vm.store(address(boomr), loc, a);
|
|
|
|
|
startHoax(victim);
|
|
|
|
|
vm.expectRevert(bytes("mission already completed"));
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice}(1);
|
|
|
|
|
vm.expectRevert(bytes("mission already completed"));
|
|
|
|
|
main.assembleBombs{value: bombPrice}(1);
|
|
|
|
|
vm.expectRevert(bytes("mission already completed"));
|
|
|
|
|
main.sendBombs(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure withdraw function works as expected
|
|
|
|
|
function testWithdrawalWorksAsOwner() public {
|
|
|
|
|
address owner = main.owner();
|
|
|
|
|
uint256 ownerStartBalance = owner.balance;
|
|
|
|
|
assertEq(address(main).balance, 0);
|
|
|
|
|
hoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice * 10}(10);
|
|
|
|
|
uint256 contractBalance = address(main).balance;
|
|
|
|
|
assertEq(contractBalance, unaboomerPrice * 10);
|
|
|
|
|
main.withdraw();
|
|
|
|
|
assertEq(owner.balance, ownerStartBalance + contractBalance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure only owner can withdraw
|
|
|
|
|
function testWithdrawalFailsAsNotOwner() public {
|
|
|
|
|
hoax(victim);
|
|
|
|
|
main.radicalizeBoomers{value: unaboomerPrice * 10}(10);
|
|
|
|
|
uint256 contractBalance = address(main).balance;
|
|
|
|
|
assertEq(contractBalance, unaboomerPrice * 10);
|
|
|
|
|
vm.expectRevert("UNAUTHORIZED");
|
|
|
|
|
hoax(address(0xd3ad));
|
|
|
|
|
main.withdraw();
|
|
|
|
|
vm.expectRevert("UNAUTHORIZED");
|
|
|
|
|
hoax(address(123));
|
|
|
|
|
main.withdraw();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ensure NFT contracts do not accept Ether
|
|
|
|
|
function testNoAcceptEther() public {
|
|
|
|
|
(bool tbb, ) = payable(address(bomb)).call{value: .5 ether}("");
|
|
|
|
|
assertEq(tbb, false);
|
|
|
|
|
(bool tbr, ) = payable(address(boomr)).call{value: .5 ether}("");
|
|
|
|
|
assertEq(tbr, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// function testURILogic() public {
|
|
|
|
|
// address t = address(1);
|
|
|
|
|
// boomr.setAliveURI('ipfs://alive/');
|
|
|
|
|
// boomr.setDeadURI('ipfs://dead/');
|
|
|
|
|
// startHoax(t);
|
|
|
|
|
// main.radicalizeBoomers{value: .01 ether}(1);
|
|
|
|
|
// assertEq(boomr.tokenURI(0), 'ipfs://alive/0.json');
|
|
|
|
|
// main.sendBombs(1);
|
|
|
|
|
// assertEq(boomr.tokenURI(0), 'ipfs://dead/0.json');
|
|
|
|
|
// }
|
|
|
|
|
// Function to receive Ether. msg.data must be empty
|
|
|
|
|
receive() external payable {}
|
|
|
|
|
|
|
|
|
|
// Fallback function is called when msg.data is not empty
|
|
|
|
|
fallback() external payable {}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|