// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; contract NFTSbt is AccessControl, ERC721Enumerable { using Counters for Counters.Counter; string private _baseTokenURI = "https://market.cebg.games/api/nft/info/"; bytes32 public constant BURN_ROLE = keccak256("BURN_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); uint256 public immutable supplyLimit; Counters.Counter private _tokenIdCounter; constructor( string memory _name, string memory _symbol, uint256 _supplyLimt ) ERC721(_name, _symbol) { supplyLimit = _supplyLimt; _setRoleAdmin(BURN_ROLE, DEFAULT_ADMIN_ROLE); _setRoleAdmin(MINTER_ROLE, DEFAULT_ADMIN_ROLE); _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); _setupRole(MINTER_ROLE, msg.sender); _setupRole(BURN_ROLE, msg.sender); } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface( bytes4 interfaceId ) public view virtual override(AccessControl, ERC721Enumerable) returns (bool) { return super.supportsInterface(interfaceId); } function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal override(ERC721Enumerable) { require(from == address(0) || to == address(0), "Token not transferable"); super._beforeTokenTransfer(from, to, tokenId); } function _baseURI() internal view virtual override returns (string memory) { return _baseTokenURI; } /** * @dev Set token URI */ function updateBaseURI( string calldata baseTokenURI ) external onlyRole(DEFAULT_ADMIN_ROLE) { _baseTokenURI = baseTokenURI; } /** * @dev one type nft has same tokenURI */ function tokenURI( uint256 tokenId ) public view virtual override returns (string memory) { string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? baseURI : ""; } function mint(address to) external onlyRole(MINTER_ROLE) returns (uint256) { require(to != address(0), "Cannot mint to zero address"); if (supplyLimit > 0) { require((totalSupply() + 1) <= supplyLimit, "Exceed the total supply"); } _tokenIdCounter.increment(); uint256 tokenId = _tokenIdCounter.current(); _safeMint(to, tokenId); return tokenId; } function burn(uint256 tokenId) external onlyRole(BURN_ROLE) { require( _isApprovedOrOwner(_msgSender(), tokenId), "Caller is not owner nor approved" ); _burn(tokenId); } /** * @dev Grant mint role to address */ function setMintRole(address to) external { grantRole(MINTER_ROLE, to); } /** * @dev Remove mint role to address */ function removeMintRole(address to) external { revokeRole(MINTER_ROLE, to); } /** * @dev Grant burn role to address */ function setBurnRole(address to) external { grantRole(BURN_ROLE, to); } /** * @dev Remove burn role to address */ function removeBurnRole(address to) external { revokeRole(BURN_ROLE, to); } }