// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts@5.0.0/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts@5.0.0/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts@5.0.0/token/ERC721/extensions/ERC721URIStorage.sol"; import "@openzeppelin/contracts@5.0.0/token/ERC721/extensions/ERC721Pausable.sol"; import "@openzeppelin/contracts@5.0.0/access/AccessControl.sol"; contract SperaBots is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Pausable, AccessControl { uint256 private _nextTokenId; bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); mapping(string uri => bool) private _mintedURIs; constructor() ERC721("Spera Bots", "SBT") { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); } modifier onlyAdmin() { require( hasRole(DEFAULT_ADMIN_ROLE, msg.sender) || hasRole(ADMIN_ROLE, msg.sender), "Unauthorized" ); _; } function addAdmin(address newAdmin) external onlyRole(DEFAULT_ADMIN_ROLE) { grantRole(ADMIN_ROLE, newAdmin); } function removeAdmin(address admin) external onlyRole(DEFAULT_ADMIN_ROLE) { revokeRole(ADMIN_ROLE, admin); } function pause() public onlyAdmin { _pause(); } function unpause() public onlyAdmin { _unpause(); } function safeMint(address to, string memory uri) public onlyAdmin { /* require(!_mintedURIs[uri], "URI already minted"); */ uint256 tokenId = _nextTokenId++; _safeMint(to, tokenId); _setTokenURI(tokenId, uri); /* _mintedURIs[uri] = true; */ } function burn(uint256 tokenId) public onlyAdmin { _update(address(0), tokenId, _msgSender()); } // The following functions are overrides required by Solidity. function _update( address to, uint256 tokenId, address auth ) internal override(ERC721, ERC721Enumerable, ERC721Pausable) returns (address) { return super._update(to, tokenId, auth); } function _increaseBalance( address account, uint128 value ) internal override(ERC721, ERC721Enumerable) { super._increaseBalance(account, value); } function tokenURI( uint256 tokenId ) public view override(ERC721, ERC721URIStorage) returns (string memory) { return super.tokenURI(tokenId); } function supportsInterface( bytes4 interfaceId ) public view override(ERC721, ERC721Enumerable, ERC721URIStorage, AccessControl) returns (bool) { return super.supportsInterface(interfaceId); } }