Compiling error in QuickNode's tutorial "How To Create a NFT smart contract (ERC1155) with Truffle?"

Hello to everybody. I am new in all this Web3. As I plan to sell art NFTs on different market places (e.g. OpenSea, NFTify and Rarible) I like to have my own smart contract.

I followed on weekend the tutorial here on Quicknode, written shortly in August 2023 by Ferhat Kochan .

With lots of twerking as “newbe” (non coder) I manage it to come to the final step for doing a “Truffle Test”.

Both in the terminal I get the same negative result directly by Truffle, as same I did in Review.Etherum with the compiler test.

TypeError: No arguments passed to the base constructor. Specify the arguments or mark “ERC1155Token” as abstract.
→ Smart Contract (Polygon Testnet)/ERC1155Token.sol:11:1:
|
11 | contract ERC1155Token is ERC1155, Ownable {
| ^ (Relevant source part starts here and spans across multiple lines).
Note: Base constructor parameters:
@openzeppelin/contracts/access/Ownable.sol:38:16:
|
38 | constructor(address initialOwner) {
| ^^^^^^^^^^^^^^^^^^^^^^

Having asked A.I: I got following hint, but it doesnt really work.

The first two warnings in your Truffle compile output are telling you that the visibility of the constructors for your MetaCoin and Migrations contracts is being ignored. This is because constructors in Solidity are always public, regardless of their visibility.

To fix these warnings, you can either change the visibility of the constructors to public or mark the contracts as abstract. Marking a contract as abstract means that it cannot be deployed directly, but only inherited from.

The third error in your Truffle compile output is telling you that you have not passed any arguments to the base constructor for your ERC1155Token contract. The base constructor for the ERC1155 contract takes one argument, which is the initial owner of the contract.

To fix this error, you need to pass the initial owner of the contract to the base constructor. You can do this by adding the following line to the constructor of your ERC1155Token contract:

*super(initialOwner);*

Here is an example of a corrected constructor for your ERC1155Token contract:

*contract ERC1155Token is ERC1155, Ownable {* *> constructor(address initialOwner) ERC1155(initialOwner) {}* *> }*

Has anybody a concrete hint ? And is it possible to send a direct message to the author Ferhat Kochan who wrote this tutorial ?

Hi LG102023,

Thank you for bringing this to our attention. It appears with OpenZeppelin upgrading their code some additional constructors are now required in our code.

I added the initialOwner argument to the constructor as well as initialized the Owner constructor with the initialOwner address.

Try the code below, I verified it compiles on Remix.IDE (using compiler version 0.8.20).

ERC1155.sol

// contracts/ERC1155Token.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract ERC1155Token is ERC1155, Ownable {

    string[] public names; //string array of names
    uint[] public ids; //uint array of ids
    string public baseMetadataURI; //the token metadata URI
    string public name; //the token mame
    uint public mintFee = 0 wei; //mintfee, 0 by default. only used in mint function, not batch.
    
    mapping(string => uint) public nameToId; //name to id mapping
    mapping(uint => string) public idToName; //id to name mapping

    /*
    constructor is executed when the factory contract calls its own deployERC1155 method
    */
    constructor(address initialOwner, string memory _contractName, string memory _uri, string[] memory _names, uint[] memory _ids) Ownable(initialOwner) ERC1155(_uri) {
        names = _names;
        ids = _ids;
        createMapping();
        setURI(_uri);
        baseMetadataURI = _uri;
        name = _contractName;
        transferOwnership(tx.origin);
    }   

    /*
    creates a mapping of strings to ids (i.e ["one","two"], [1,2] - "one" maps to 1, vice versa.)
    */
    function createMapping() private {
        for (uint id = 0; id < ids.length; id++) {
            nameToId[names[id]] = ids[id];
            idToName[ids[id]] = names[id];
        }
    }
    /*
    sets our URI and makes the ERC1155 OpenSea compatible
    */
    function uri(uint256 _tokenid) override public view returns (string memory) {
        return string(
            abi.encodePacked(
                baseMetadataURI,
                Strings.toString(_tokenid),".json"
            )
        );
    }

    function getNames() public view returns(string[] memory) {
        return names;
    }

    /*
    used to change metadata, only owner access
    */
    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    /*
    set a mint fee. only used for mint, not batch.
    */
    function setFee(uint _fee) public onlyOwner {
        mintFee = _fee;
    }

    /*
    mint(address account, uint _id, uint256 amount)

    account - address to mint the token to
    _id - the ID being minted
    amount - amount of tokens to mint
    */
    function mint(address account, uint _id, uint256 amount) 
        public payable returns (uint)
    {
        require(msg.value == mintFee);
        _mint(account, _id, amount, "");
        return _id;
    }

    /*
    mintBatch(address to, uint256[] memory _ids, uint256[] memory amounts, bytes memory data)

    to - address to mint the token to
    _ids - the IDs being minted
    amounts - amount of tokens to mint given ID
    bytes - additional field to pass data to function
    */
    function mintBatch(address to, uint256[] memory _ids, uint256[] memory amounts, bytes memory data)
        public
    {
        _mintBatch(to, _ids, amounts, data);
    }
}

You may also need to update the Factory contract as well. It appears this is the only snippet that needs to be updated:

    function deployERC1155(address initialOwner, string memory _contractName, string memory _uri, uint[] memory _ids, string[] memory _names) public returns (address) {
        ERC1155Token t = new ERC1155Token(initialOwner, _contractName, _uri, _names, _ids);
        tokens.push(t);
        indexToContract[tokens.length - 1] = address(t);
        indexToOwner[tokens.length - 1] = tx.origin;
        emit ERC1155Created(msg.sender,address(t));
        return address(t);
    }

You may get some warnings from Remix.IDE regarding the contract potentially being un-deployable on mainnet (due to size limits) so you should enable optimizations to reduce the size of your smart contract.

Also note that Truffle is no longer being maintained so i’d recommend checking out one of our Hardhat or Foundry guides to learn more about smart contract development frameworks.

Hope that helps. Let me know if you have any other questions.

Thank you,

Regards,
Senior Technical Writer
Ferhat