diff --git a/src/Main.sol b/src/Main.sol index 5e79859..58aab09 100644 --- a/src/Main.sol +++ b/src/Main.sol @@ -135,7 +135,7 @@ contract Main is Owned { /// The game stops; no more bombing/killing. Survivors make it to the next round. modifier missionNotCompleted { require( - unaboomer.totalKillCount() < (unaboomer.MAX_SUPPLY() - unaboomer.MAX_SURVIVOR_COUNT()), + unaboomer.burned() < (unaboomer.MAX_SUPPLY() - unaboomer.MAX_SURVIVOR_COUNT()), "mission already completed" ); _; @@ -154,14 +154,14 @@ contract Main is Owned { /// Get BOOMR token total supply /// @return supply Amount of BOOMR tokens minted in total - function unaboomerSupply() public view returns (uint256) { - return unaboomer.totalSupply(); + function unaboomersMinted() public view returns (uint256) { + return unaboomer.minted(); } /// Get BOOMR kill count (unaboomers killed) /// @return killCount Amount of BOOMR tokens "killed" (dead pfp) - function unaboomersKilled() public view returns (uint256) { - return unaboomer.totalKillCount(); + function unaboomersBurned() public view returns (uint256) { + return unaboomer.burned(); } /// Get BOOMR token max supply @@ -185,7 +185,7 @@ contract Main is Owned { /// Get BOMB token supply /// @return supply Amount of BOMB tokens ever minted / "assembled" - function bombSupply() public view returns (uint256) { + function bombsAssembled() public view returns (uint256) { return mailbomb.bombsAssembled(); } @@ -222,8 +222,8 @@ contract Main is Owned { /// @param _amount Amount of bombs to send to kill Unaboomers (dead pfps) function sendBombs(uint256 _amount) external missionNotCompleted { // Ensure _amount will not exceed wallet balance of bombs, Unaboomer supply, and active Unaboomers - uint256 supply = unaboomer.totalSupply(); - uint256 killed = unaboomersKilled(); + uint256 supply = unaboomersMinted(); + uint256 killed = unaboomersBurned(); require(_amount <= bombBalance(msg.sender), "not enough bombs"); require(_amount <= supply, "not enough supply"); require(_amount <= supply - killed, "not enough active boomers"); diff --git a/src/Unaboomer.sol b/src/Unaboomer.sol index 3e443b5..f19ffca 100644 --- a/src/Unaboomer.sol +++ b/src/Unaboomer.sol @@ -27,12 +27,12 @@ contract Unaboomer is ERC721, Owned { /// Track if a BOOMR token is toggled as alive or dead mapping(uint256 => bool) public tokenDead; /// Maximum supply of BOOMR tokens - uint256 public constant MAX_SUPPLY = 10000; + uint256 public constant MAX_SUPPLY = 35000; /// Maximum amount of survivors remaining to advance to the next round - uint256 public constant MAX_SURVIVOR_COUNT = 1000; - /// The total amount of Unaboomers who have been killed during the game - uint256 public totalKillCount; - /// Number of tokens minted (total supply) + uint256 public constant MAX_SURVIVOR_COUNT = 10000; + /// Amount of Unaboomers killed (tokens burned) + uint256 public burned; + /// Amount of Unaboomers radicalized (tokens minted) uint256 public minted; /// Base URI for living Unaboomers - original pixelated avatars string public aliveURI; @@ -82,14 +82,14 @@ contract Unaboomer is ERC721, Owned { /// Helper function to get supply minted /// @return supply Number of Unaboomers radicalized in totality (minted) function totalSupply() public view returns (uint256) { - return minted; + return minted - burned; } /// Mint tokens from main contract /// @param _to Address to mint BOOMR tokens to /// @param _amount Amount of BOOMR tokens to mint function radicalize(address _to, uint256 _amount) external onlyMain { - require(totalSupply() + _amount <= MAX_SUPPLY, "supply reached"); + require(minted + _amount <= MAX_SUPPLY, "supply reached"); for (uint256 i; i < _amount; i++) { minted++; _safeMint(_to, minted); @@ -97,20 +97,28 @@ contract Unaboomer is ERC721, Owned { } /// Toggle token state from living to dead - /// @param tokenId Token ID of BOOMR to toggle living -> dead and increment kill count - function die(uint256 tokenId) external onlyMain { - require(tokenId <= totalSupply(), "invalid token id"); - if (tokenDead[tokenId] == false) { - totalKillCount++; - tokenDead[tokenId] = true; + /// @param _tokenId Token ID of BOOMR to toggle living -> dead and increment kill count + function die(uint256 _tokenId) external onlyMain { + require(_tokenId <= minted, "invalid token id"); + if (ownerOf(_tokenId) != address(0)) { + burned++; + _burn(_tokenId); } } + /// Retrieve owner of given token ID + /// @param _tokenId Token ID to check owner of + /// @return owner Address of owner + /// @dev Overridden from Solmate contract to allow zero address returns + function ownerOf(uint256 _tokenId) public view override returns (address owner) { + return _ownerOf[_tokenId]; + } + // Return URI to retrieve JSON metadata from - points to images and descriptions /// @param _tokenId Token ID of BOOMR to fetch URI for /// @return string IPFS or HTTP URI to retrieve JSON metadata from function tokenURI(uint256 _tokenId) public view override returns (string memory) { - if (tokenDead[_tokenId] == true) { + if (ownerOf(_tokenId) == address(0)) { return string(abi.encodePacked(deadURI, _tokenId.toString(), ".json")); } else { return string(abi.encodePacked(aliveURI, _tokenId.toString(), ".json")); diff --git a/test/Unaboomer.t.sol b/test/Unaboomer.t.sol index c7f91f3..a35681e 100644 --- a/test/Unaboomer.t.sol +++ b/test/Unaboomer.t.sol @@ -57,7 +57,7 @@ contract UnaboomerTest is Test { main.sendBombs(3); main.sendBombs(3); assertEq(main.leaderboard(main.leaderboardPointer()), killer); - assertEq(main.unaboomersKilled() > 0, true); + assertEq(main.unaboomersBurned() > 0, true); console.log(main.killCount(killer)); } @@ -66,7 +66,7 @@ contract UnaboomerTest is Test { boomr.setAliveURI('ipfs://alive/'); boomr.setDeadURI('ipfs://dead/'); startHoax(victim); - main.radicalizeBoomers{value: unaboomerPrice * 1}(1); + main.radicalizeBoomers{value: unaboomerPrice}(1); assertEq(boomr.tokenURI(1), 'ipfs://alive/1.json'); main.sendBombs(1); assertEq(boomr.tokenURI(1), 'ipfs://dead/1.json'); @@ -95,7 +95,7 @@ contract UnaboomerTest is Test { bytes32 loc = bytes32(slot); bytes32 mockedCurrentTokenId = bytes32(abi.encode(maxSupply - 1)); vm.store(address(boomr), loc, mockedCurrentTokenId); - assertEq(main.unaboomerSupply(), (maxSupply - 1)); + assertEq(main.unaboomersMinted(), (maxSupply - 1)); startHoax(victim); main.radicalizeBoomers{value: unaboomerPrice}(1); vm.expectRevert(bytes("supply reached")); @@ -115,7 +115,7 @@ contract UnaboomerTest is Test { vm.store(address(boomr), loc, a); slot = stdstore .target(address(boomr)) - .sig("totalKillCount()") + .sig("burned()") .find(); loc = bytes32(slot); a = bytes32(abi.encode((maxSupply - maxSurvivorCount))); // 1k