// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; /******* Mint Mechanics .00 per unaboomer (BOOMR) - 10k supply .02 per bomb (BOMB) - infinite supply BOMB holders can randomly mail bombs to other owners 1 BOMB kills 1 BOOMR - BOOMR image switches to explosion after being bombed chaos ensues until 1000 survivors - the game stops ********/ import {ERC721} from "solmate/tokens/ERC721.sol"; import {LibString} from "solmate/utils/LibString.sol"; error NotOwnerOfToken(); error MaxSupplyReached(); error TooMany(); error NoContract(); error WrongEtherAmount(); error MaxAmountReached(); error NoAdmins(); error NotAdmin(); error NoRemoveSelf(); error NoRemoveDeployer(); contract Unaboomer is ERC721 { using LibString for uint256; mapping(uint256 => bool) public tokenDead; mapping(address => bool) public adminWallets; uint256 public constant MAX_SUPPLY = 10000; uint256 public minted; string public livingURI; string public deadURI; address public deployer; address[] public payoutWallets; constructor() ERC721("Unaboomer", "BOOMR") { deployer = msg.sender; adminWallets[msg.sender] = true; } // ========================================================================= // Admin // ========================================================================= modifier onlyAdmin { if (adminWallets[msg.sender] == false) revert NotAdmin(); _; } ///@dev Specify team wallets for payouts and contract administration function updateAdmins(address[] calldata _admins) external onlyAdmin { payoutWallets = _admins; for (uint256 i; i < _admins.length; i++) { adminWallets[_admins[i]] = true; } } ///@dev Remove admins if needed function removeAdmin(address _admin) external onlyAdmin { if (msg.sender == _admin) revert NoRemoveSelf(); if (_admin == deployer) revert NoRemoveDeployer(); adminWallets[_admin] = false; } ///@dev Split payments to team function withdraw() external onlyAdmin { if (payoutWallets.length == 0) revert NoAdmins(); uint256 balance = address(this).balance; for (uint256 i; i < payoutWallets.length; i++) { // payable(payoutWallets[i]).transfer(balance / payoutWallets.length); (bool success, ) = payable(payoutWallets[i]).call{value: balance / payoutWallets.length}(""); require(success, "failed to withdraw"); } } function setLivingURI(string calldata _baseURI) external onlyAdmin { livingURI = _baseURI; } function setDeadURI(string calldata _baseURI) external onlyAdmin { deadURI = _baseURI; } // ========================================================================= // Tokens // ========================================================================= function mint(uint256 _amount) external payable { if (msg.sender == tx.origin) revert NoContract(); if (_amount > 20) revert TooMany(); if (minted + _amount > MAX_SUPPLY) revert MaxSupplyReached(); unchecked { for (uint256 i; i < _amount; i++) { _mint(msg.sender, minted + 1); minted++; } } } function totalSupply() view public returns (uint256 supply) { return minted; } function tokenURI(uint256 _tokenId) public view override returns (string memory) { if (tokenDead[_tokenId] == false) { return string(abi.encodePacked(livingURI, _tokenId.toString(), ".json")); } else { return string(abi.encodePacked(deadURI, _tokenId.toString(), ".json")); } } function supportsInterface(bytes4 interfaceId) public view virtual override (ERC721) returns (bool) { return super.supportsInterface(interfaceId); } }