# How to create a non-transferrable, burnable ERC721?

**URL:** https://forum.openzeppelin.com/t/how-to-create-a-non-transferrable-burnable-erc721/2427
**Category:** Contracts
**Created:** [March 5, 2020, 9:10pm UTC](https://forum.openzeppelin.com/t/how-to-create-a-non-transferrable-burnable-erc721/2427 "2020-03-05T21:10:59Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)
#### Post date: [March 5, 2020, 9:10pm UTC](https://forum.openzeppelin.com/t/how-to-create-a-non-transferrable-burnable-erc721/2427/1 "2020-03-05T21:10:59Z")

</div>

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

---

<div class="post-metadata">

### Author: ![abcoathup](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/abcoathup/32/415_2.png) [@abcoathup](https://forum.openzeppelin.com/u/abcoathup)
#### Post date: [March 6, 2020, 7:06am UTC](https://forum.openzeppelin.com/t/how-to-create-a-non-transferrable-burnable-erc721/2427/2 "2020-03-06T07:06:20Z")

</div>

## NonTransferrableERC721Token.sol

Uses OpenZeppelin 3.0 Release Candidate

⚠ This contract has not been tested nor audited

```auto
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);
    }
}

```

---

<div class="post-metadata">

### Author: ![Oli8](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/oli8/32/14037_2.png) [@Oli8](https://forum.openzeppelin.com/u/Oli8)
#### Post date: [March 23, 2022, 2:19pm UTC](https://forum.openzeppelin.com/t/how-to-create-a-non-transferrable-burnable-erc721/2427/3 "2022-03-23T14:19:15Z")

</div>

Looks good to me, thank you.
