My question may be very beginner, but I can't find examples or ways to apply this, for a better explanation I'm putting my ERC20 and ERC721 code below

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";

contract HeroToken is Ownable, ERC721URIStorage {
  using Counters for Counters.Counter;
  Counters.Counter private _tokenIds;
  //event para novos hero invocados
  event CreatedNewHero(uint heroId, string uri);
  constructor() ERC721("HeroToken", "HERT") {}

  function invokeRandomHero(address _player, string memory _tokenURI) public{
     ////// add here a verification of token ERC720. How do I do it? /////


    uint256 newHeroId = _tokenIds.current();
    _mint(_player, newHeroId);
    _setTokenURI(newHeroId, _tokenURI);

    emit CreatedNewHero(newHeroId, _tokenURI);        

  function totalHeroes() public view returns(uint){
    return _tokenIds.current();


My ERC720

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract TokenCoin is ERC20, ERC20Burnable, Pausable, AccessControl, Ownable  {
    using SafeMath for uint256;

    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor() ERC20("TOKEN COIN", "TCOIN") {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setupRole(PAUSER_ROLE, msg.sender);
        _mint(msg.sender, 100000 * 10 ** decimals());
        _setupRole(MINTER_ROLE, msg.sender);                

    function pause() public onlyRole(PAUSER_ROLE) {

    function unpause() public onlyRole(PAUSER_ROLE) {

    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        _mint(to, amount);        

    function _beforeTokenTransfer(address from, address to, uint256 amount)
        super._beforeTokenTransfer(from, to, amount);


Well, what do I need? I need that the moment the "invokeRandomHero" function is called, check if the player has an X number from my "Token Coin", if he has the balance he can coin a hero and then need to burn the X value of my ERC20 ( Token Coin).

The question that remains is how can I do this? I've been looking for the last few days and I can't find any example for this situation.

I appreciate all the help.

1 Answer 1


Try researching ERC1155. It's a much cleaner standard for combining nft and token currencies in one contract, and OpenZeppelin has an implementation ready for you as well. It will allow you to manipulate both in one contract without overlapping ownership or events or anything (like you probably currently have).

OpenZeppelin docs here: https://docs.openzeppelin.com/contracts/3.x/api/presets#ERC1155PresetMinterPauser

In pseudocode:

contract HeroToken is IERC1155 {
    constructor() {
        // 0 token id is TokenCoin representation
        _mint(msg.sender, 0, 100000, "");

    function invokeRandomHero(address _player, string memory _tokenUri) public {
        burn(msg.sender, 0, 100);
        _mint(_player, _tokenIds.current(), 1, ""); // nft has just one

        // continue...
  • Thanks for the response, I will be researching this contract. If I'm not going to abuse your kindness, would you have an example that would solve my situation? Thanks again!!!
    – Crazy
    Oct 29, 2021 at 17:48
  • Updated my answer with some code. It's not gonna compile probably, but it illustrates how this could be done Oct 29, 2021 at 20:32
  • Thanks for the answer. I've been reading about this Smart Contract, however, I don't think it would solve my question, because I need the currency to be something I can trade on the market, for example, pancake among other exchanges... As I understand my TokenCoin wouldn't have that possibility, right?
    – Crazy
    Oct 30, 2021 at 6:13
  • Seems like PancakeSwap specifically only allows ERC20: docs.pancakeswap.finance/products/pancakeswap-exchange/trade. however, you can implement the IERC20 interface and allow people to trade around the TokenCoin itself, which would totally let you list it there Oct 30, 2021 at 21:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.