How to create a non-transferrable, burnable ERC721?

Asked in a discord community: How to create a non-transferable, burnable ERC721

1 Like

NonTransferrableERC721Token.sol

Uses OpenZeppelin 3.0 Release Candidate

:warning: This contract has not been tested nor audited

pragma solidity ^0.6.0;

import "@openzeppelin/contracts/token/ERC721/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract NonTransferrableERC721Token is ERC721Enumerable, ERC721Metadata, ERC721Burnable, AccessControl {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant BASEURI_SETTER_ROLE = keccak256(
        "BASEURI_SETTER_ROLE"
    );

    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() public ERC721Metadata("Simple ERC721 Token", "SIM") {
        _grantRole(MINTER_ROLE, msg.sender);
        _grantRole(BASEURI_SETTER_ROLE, msg.sender);

        _setBaseURI("https://example.com/tokens/");
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        virtual
        override(ERC721Enumerable, ERC721Metadata, ERC721)
    {
        require(from == address(0) || to == address(0), "NonTransferrableERC721Token: non transferrable");
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function mint(address to) public {
        require(
            hasRole(MINTER_ROLE, msg.sender),
            "NonTransferrableERC721Token: account does not have minter role"
        );
        _tokenIds.increment();

        uint256 newTokenId = _tokenIds.current();
        _mint(to, newTokenId);
        _setTokenURI(newTokenId, Strings.fromUint256(newTokenId));
    }

    function setBaseURI(string memory baseURI) public {
        require(
            hasRole(BASEURI_SETTER_ROLE, msg.sender),
            "NonTransferrableERC721Token: account does not have setter role"
        );
        _setBaseURI(baseURI);
    }
}
1 Like

Looks good to me, thank you.