'totalsupply() is not a function openzeppelin contracts

I'm trying to import some contract files from open zeppelin so my solidity smart contracts can inherit their functionality, when trying to write chai tests that run on my smart contracts at compile time I get an error in my chai test.

  3 passing (2s)
  1 failing

  1) Contract: Color
       minting
         creates a new token:
     TypeError: contract.totalSupply is not a function

my contract importing the openzeppelin contracts

pragma solidity 0.8.7;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; //import base functionality
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; //import totalsupply()

contract color is ERC721 {
    string[] public colors;
    mapping(string => bool) _colorExists; //mappings are like json objects where value a is searched and its value is returned
    constructor() ERC721("Color", "COLOR") {
    }

    function mint(string memory _color) public{
      colors.push(_color);
      uint _id = colors.length -1;

      _mint(msg.sender,_id);
      _colorExists[_color] = true;
 
    }
}

and lastly my test file ( I have shortened it to show only the test giving me errors)

const { assert } = require('chai')
const Color = artifacts.require('./Color.sol')

require('chai')
.use(require('chai-as-promised'))
.should()

contract('Color', (accounts) =>{
    let FormControlStatic

    before(async ()=>{
        contract = 
        await Color.deployed()
    })
    
    describe('minting', async ()=>{
        
        it('creates a new token', async ()=>{
            const result = await contract.mint('#EC058E')
            console.log(result)
            const totalSupply = await contract.totalSupply()

            assert.equal(totalSupply,1)
            console.log(result)
        })
    })
})

also if we look at the file containing the function totalSupply() it is publicly scoped so it should be visible outside the function via import

I did some digging and imported the file that the actual function IS in from openzeppelin however it seems that I still get the same error, I tried compiling separately to see if recompiling after changing would resolve but it didn't

not sure if anyone else has gone through this recently or might have a solution also I'm importing the current version here https://www.npmjs.com/package/@openzeppelin/contracts

thanks!



Solution 1:[1]

Below is a complete implementation of the smart contract.

As you mentioned in the question, it uses newer versions than the tutorial:

  • Solidity (0.8.0)
  • Open Zeppelin (4.3.2)
pragma solidity ^0.8.0; // Note that this is using a newer version than in 

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";


contract Color is ERC721, ERC721Enumerable {
    string[] public colors;
    mapping(string => bool) _colorExists;

    constructor() ERC721("Color", "COLOR") public {
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
    internal
    override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721, ERC721Enumerable)
    returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }


    function mint(string memory _color) public {
        colors.push(_color);
        uint _id = colors.length - 1;
        _mint(msg.sender, _id);
        _colorExists[_color] = true;
    }
}


You can also take a look at OpenZeppelin's section about Extending Contracts to learn about overrides and super.

Solution 2:[2]

We must extend IERC721Enumerable contracts, and, implements its virtual functions.

contract Color is ERC721, IERC721Enumerable { // We must extends IERC721Enumerable 
    string[] public colors;
    mapping(string => bool) _colorExists;

    constructor() ERC721("Color", "COLOR") {}

    function mint(string memory _color) public {
        colors.push(_color);
        uint256 _id = colors.length - 1;

        // _mint(msg.sender,_id);
        _colorExists[_color] = true;
    }
    

    // And must override below three functions

    function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
        // You need update this logic.
        // ...
        return 3;
    }

    function totalSupply() external  view override returns (uint256) {
      // You need update this logic.
      // ...
      return 1;
    }

    function tokenByIndex(uint256 index) external view  override returns (uint256) {
      // You need update this logic.
      // ...
      return 5;
    }
}

enter image description here

Then, we can call totalSupply() method

Solution 3:[3]

You can follow these following steps to continue the tutorial.

  • First create a new contract file with ERC721Enumerable:
 ./node_modules/.bin/truffle-flattener ./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol > contracts/ERC721Enumerable.sol
  • Second replace old ERC721 with new ERC721Enumerable:
import "./ERC721Enumerable.sol";
     
contract Color is ERC721Enumerable {
         // 
     }
  • Delete old ERC721Full.sol files under the contracts folder.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3