Running in Testnet server (rinkeby) [I CLONED RARABLE IN 24 HOURS pt7]

Im trying to mint nft using the moralis testnet server Eth (rinkeby) as my network does not allow access of localDev proxy configuration using Ganache.

Im stuck on configuring the tokenContractAbi and receiving this error:

This is my createItem method:

createItem = async () => {
    if (createItemFile.files.length == 0){
        alert("Please select a file!");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please give the item a name!");
        return;
    }

    mintNft = async (metadataURL) => {
        const receipt = await tokenContract.methods.createItem(metadataURL).send({from: ethereum.selectedAddress});
        console.log(receipt);
        return receipt.events.Transfer.returnValues.tokenId;
    }

const nftFile = new Moralis.File("nftFile.webp", createItemFile.files[0]);
await nftFile.saveIPFS();

const nftFilePath = nftFile.ipfs();
const nftFileHash= nftFile.hash();

const metadata = {
    name: createItemNameField.value,
    description: createItemDescriptionField.value,
    image: nftFilePath,
};

const nftFileMetadataFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
await nftFileMetadataFile.saveIPFS();

const nftFileMetadataFilepath = nftFileMetadataFile.ipfs();
const nftFileMetadataFileHash = nftFileMetadataFile.hash();

const nftId = await mintNft(nftFileMetadataFilePath);

const Item = Moralis.Object.extend("Item");

const item = new Item();
item.set('name', createItemNameField.value);
item.set('description', createItemDescriptionField.value);
item.set('nftFilePath', nftFilePath);
item.set('nftFileHash', nftFileHash);
item.set('metadataFilePath', nftFileMetadataFilepath);
item.set('metadataFileHash', nftFileMetadataFileHash);
item.set('nftId', nftId);
item.set('nftContractAddress', TOKEN_CONTRACT_ADDRESS);
await item.save();
alert("Item uploaded successfully!");
console.log(item);

}

With this i call it using:

init = async () => {
    hideElement(userInfo);
    hideElement(createItemForm);
    await Moralis.enableWeb3();
    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
        initUser();
}

This is my abi.js file:

var tokenContractAbi = [
    {
      "inputs": [],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "approved",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "Approval",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "operator",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "bool",
          "name": "approved",
          "type": "bool"
        }
      ],
      "name": "ApprovalForAll",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "Items",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        },
        {
          "internalType": "address",
          "name": "creator",
          "type": "address"
        },
        {
          "internalType": "string",
          "name": "uri",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "approve",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getApproved",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "operator",
          "type": "address"
        }
      ],
      "name": "isApprovedForAll",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "ownerOf",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "safeTransferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "internalType": "bytes",
          "name": "_data",
          "type": "bytes"
        }
      ],
      "name": "safeTransferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "operator",
          "type": "address"
        },
        {
          "internalType": "bool",
          "name": "approved",
          "type": "bool"
        }
      ],
      "name": "setApprovalForAll",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes4",
          "name": "interfaceId",
          "type": "bytes4"
        }
      ],
      "name": "supportsInterface",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "transferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "string",
          "name": "uri",
          "type": "string"
        }
      ],
      "name": "createItem",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "tokenURI",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    }
  ]

You need to correct your const nftId = await mintNft(nftFileMetadataFilePath);, it should be nftFileMetadataFilepath based on the variable name above. Or just make all of them match.

i seem to be getting these errors also.

These errors don’t seem to be from the createItem code you posted, you can post the rest. How have you imported web3.js?

this is the rest of my code.

JS:


const serverUrl = "https://aunhzmktt38i.usemoralis.com:2053/server";
const appId = "xqd9drEGLrONEC8AoI8ShKH1G9FK4ezBDM0TXAXz";
const TOKEN_CONTRACT_ADDRESS = "0x80909d0DF877291cfe919AE14a659697b8a6B8fc";




Moralis.start({ serverUrl, appId, TOKEN_CONTRACT_ADDRESS });

init = async () => {
    hideElement(userInfo);
    hideElement(createItemForm);
    await Moralis.enableWeb3();
    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
        initUser();
}

initUser = async () => {
    if (await Moralis.User.current()){
        hideElement(userConnectButton);
        showElement(userProfileButton);
        showElement(openCreateItemButton);

    }else{
        showElement(userConnectButton);
        hideElement(userProfileButton);
        hideElement(openCreateItemButton);
        hideElement(createItemForm);
    }
}

login = async () => {
    try {
        await Moralis.authenticate();
        initUser();
    } catch (error) {
        alert(error)
    }
}

logout = async () => {
    await Moralis.User.logOut();
    hideElement(userInfo);
    initUser();
}

openUserInfo = async () => {
    user = await Moralis.User.current();
    if (user){    
        const email = user.get('email');
        if(email){
            userEmailField.value = email;
        }else{
            userEmailField.value = "";
        }

        userNameField.value = user.get('username');

        const userAvatar = user.get('avatar');
        if(userAvatar){
            userAvatarImg.src = userAvatar.url();
            showElement(userAvatarImg);
        }else{
            hideElement(userAvatarImg);
        }

        showElement(userInfo);
    }else{
        login();
    }
}

saveUserInfo = async () => {
    user.set('email', userEmailField.value);
    user.set('username', userNameField.value);

    if (userAvatarFile.files.length > 0) {
        const avatar = new Moralis.File("avatar1.jpg", userAvatarFile.files[0]);
        user.set('avatar', avatar);
    }

    await user.save();
    alert("User info saved successfully!");
    openUserInfo();
}

createItem = async () => {
    if (createItemFile.files.length == 0){
        alert("Please select a file!");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please give the item a name!");
        return;
    }

    mintNft = async (metadataUrl) => {
        const receipt = await tokenContract.methods.createItem(metadataUrl).send({from: ethereum.selectedAddress});
        console.log(receipt);
        return receipt.events.Transfer.returnValues.tokenId;
    }

const nftFile = new Moralis.File("nftFile.webp", createItemFile.files[0]);
await nftFile.saveIPFS();

const nftFilePath = nftFile.ipfs();
const nftFileHash= nftFile.hash();

const metadata = {
    name: createItemNameField.value,
    description: createItemDescriptionField.value,
    image: nftFilePath,
};

const nftFileMetadataFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
await nftFileMetadataFile.saveIPFS();

const nftFileMetadataFilepath = nftFileMetadataFile.ipfs();
const nftFileMetadataFileHash = nftFileMetadataFile.hash();

const nftId = await mintNft(nftFileMetadataFilePath);

const Item = Moralis.Object.extend("Item");

const item = new Item();
item.set('name', createItemNameField.value);
item.set('description', createItemDescriptionField.value);
item.set('nftFilePath', nftFilePath);
item.set('nftFileHash', nftFileHash);
item.set('metadataFilePath', nftFileMetadataFilepath);
item.set('metadataFileHash', nftFileMetadataFileHash);
item.set('nftId', nftId);
item.set('nftContractAddress', TOKEN_CONTRACT_ADDRESS);
await item.save();
alert("Item uploaded successfully!");
console.log(item);

}

hideElement = (element) => element.style.display = "none";
showElement = (element) => element.style.display = "block";

const userConnectButton = document.getElementById("btnConnect");
userConnectButton.onclick = login;

const userProfileButton = document.getElementById("btnUserInfo");
userProfileButton.onclick = openUserInfo;

const userInfo = document.getElementById("userInfo");
const userNameField = document.getElementById("txtUsername");
const userEmailField = document.getElementById("txtEmail");
const userAvatarImg = document.getElementById("imgAvatar");
const userAvatarFile = document.getElementById("fileAvatar");


document.getElementById("btnCloseUserInfo").onclick = () => hideElement(userInfo);
document.getElementById("btnLogOut").onclick = logout;
document.getElementById("btnSaveUserInfo").onclick = saveUserInfo;

const createItemForm = document.getElementById("createItem");

const createItemNameField = document.getElementById("txtCreateItemName");
const createItemDescriptionField = document.getElementById("txtCreateItemDescription");
const createItemPriceField = document.getElementById("numCreateItemPrice");
const createItemStatusField = document.getElementById("selectCreateItemStatus");
const createItemFile = document.getElementById("fileCreateItemFile");

const openCreateItemButton = document.getElementById("btnOpenCreateItem");
openCreateItemButton.onclick = () => showElement(createItemForm);
document.getElementById("btnCloseCreateItem").onclick = () => hideElement(createItemForm);
document.getElementById("btnCreateItem").onclick = createItem;


init();

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Morarables</title>
</head>
<body>
    <div>
        <button id="btnConnect">Connect Wallet</button>
        <button id="btnUserInfo">Profile</button>
        <button id="btnOpenCreateItem">Create</button>

    </div>

    <div id="userInfo">
        <h4>User Profile</h4>
        <input type="text" id="txtUsername" required placeholder="Enter username">
        <input type="text" id="txtEmail" placeholder="Enter email">
        <small>Optional</small>

        <img width="50" height="50" src="" id="imgAvatar" alt="">
        <label for="fileAvatar">Select Avatar</label>
        <input type="file" id="fileAvatar">

        <button id="btnLogOut">Log out</button>
        <button id="btnCloseUserInfo">Close</button>
        <button id="btnSaveUserInfo">Save</button>
    </div>

    <div id="createItem">
        <h4>Create Item</h4>
        <input type="text" id="txtCreateItemName" required placeholder="Enter name">
        <textarea id="txtCreateItemDescription" cols="30" rows="5" placeholder="Enter description"></textarea>
        <input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required>
    
        <label for="selectCreateItemStatus">Status</label>
        <select id="selectCreateItemStatus">        
            <option value="0">Not for sale</option>
            <option value="1">Instant buy</option>
            <option value="2">Accept Offers</option>
        </select>

        <label for="fileCreateItemFile">Select File</label>
        <input type="file" id="fileCreateItemFile">

        <button id="btnCloseCreateItem">Close</button>
        <button id="btnCreateItem">Create!</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <script src="abi.js"></script>
    <script src="main.js"></script>
</body>
</html>

You need to create a web3.js instance.

init = async () => {
  hideElement(userInfo);
  hideElement(createItemForm);
  await Moralis.enableWeb3();

  web3 = new Web3(web3.currentProvider); // create instance

  window.tokenContract = new web3.eth.Contract(
    tokenContractAbi,
    TOKEN_CONTRACT_ADDRESS
  );
  initUser();
};

Also you should move your web3.js and Moralis scripts into your index.html head.

that seems to fix the issue but another has arisen:

this appears after the ‘Create!’ button is pressed.

Moving the scripts to the head brings up an Uncaught TypeError and a MetaMask - RPC Error: TxGasUtil - Trying to call a function on a non-contract address

Moving the scripts to the head brings up an Uncaught TypeError

Move it back if that’s the case; works fine on my end and typically you place these library scripts in the head.

You need to check your TOKEN_CONTRACT_ADDRESS, 0x80909d0DF877291cfe919AE14a659697b8a6B8fc does not seem to be a contract.

I have changed my localnet (ganache) to testnet (Rinkeby). Should i go through the process in terminal using the same command (truffle migrate)?

Yes that hardcoded TOKEN_CONTRACT_ADDRESS needs to be a contract on Rinkeby since you’re not using your local network.