Metamask & Moralis Rarible Tutorial

Hi guys hope all is well. I’m having an issue when trying to mint an NFT on the site. Up to episode 7. When clciking create the following appears on Metamask: ALERT: Transaction Error. Exception thrown in contract code. the console shows the following: Thanks as always guys your always so helpful on this forum.

inpage.js:1 You are accessing the MetaMask window.web3.currentProvider shim. This property is deprecated; use window.ethereum instead. For details, see: https://docs.metamask.io/guide/provider-migration.html#replacing-window-web3
get @ inpage.js:1
inpage.js:1 MetaMask: The event 'close' is deprecated and may be removed in the future. Please use 'disconnect' instead.
For more information, see: https://eips.ethereum.org/EIPS/eip-1193#disconnect
_warnOfDeprecation @ inpage.js:1
inpage.js:1 MetaMask: 'ethereum.enable()' is deprecated and may be removed in the future. Please use the 'eth_requestAccounts' RPC method instead.
For more information, see: https://eips.ethereum.org/EIPS/eip-1102
enable @ inpage.js:1
moralis.js:1792 WebSocket connection to 'wss://snpebh67zxfb.moralis.io:2053/server' failed: 
value @ moralis.js:1792
moralis.js:1792 WebSocket connection to 'wss://snpebh67zxfb.moralis.io:2053/server' failed: 
value @ moralis.js:1792
moralis.js:1792 WebSocket connection to 'wss://snpebh67zxfb.moralis.io:2053/server' failed: 
value @ moralis.js:1792
moralis.js:1792 WebSocket connection to 'wss://snpebh67zxfb.moralis.io:2053/server' failed: 
value @ moralis.js:1792
moralis.js:1792 WebSocket connection to 'wss://snpebh67zxfb.moralis.io:2053/server' failed: 
value @ moralis.js:1792
inpage.js:1 MetaMask - RPC Error: Error: [ethjs-query] while formatting outputs from RPC '{"value":{"code":-32603,"data":{"message":"VM Exception while processing transaction: revert","code":-32000,"data":{"0x0de35c9758c46c3756b788393dacf7a9317712ccf4cd41ef4d68ab473bcc9987":{"error":"revert","program_counter":70,"return":"0x"},"stack":"RuntimeError: VM Exception while processing transaction: revert\n    at Function.RuntimeError.fromResults (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n    at BlockchainDouble.processBlock (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:24)\n    at runMicrotasks (<anonymous>)\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)","name":"RuntimeError"}}}}' {code: -32603, message: "Error: [ethjs-query] while formatting outputs from…/task_queues.js:93:5)","name":"RuntimeError"}}}}'"}
(anonymous) @ inpage.js:1
(anonymous) @ inpage.js:17
_runReturnHandlers @ inpage.js:17
_processRequest @ inpage.js:17
async function (async)
_processRequest @ inpage.js:17
_handle @ inpage.js:17
handle @ inpage.js:17
_rpcRequest @ inpage.js:1
(anonymous) @ inpage.js:1
request @ inpage.js:1
bound bound request @ util.js:693
c.send @ index.js:156
h @ index.js:615
(anonymous) @ index.js:633
o @ index.js:533
a @ util.js:689
b.run @ browser.js:153
p @ browser.js:123
setTimeout (async)
u @ browser.js:41
o.nextTick @ browser.js:143
(anonymous) @ util.js:694
Promise.then (async)
bound bound request @ util.js:694
c.send @ index.js:156
h @ index.js:615
n @ index.js:642
n @ index.js:624
d._executeMethod @ index.js:841
mintNft @ main.js:180
createItem @ main.js:161
async function (async)
createItem @ main.js:146
main.js:177 Uncaught (in promise) {code: -32603, message: "Error: [ethjs-query] while formatting outputs from…/task_queues.js:93:5)","name":"RuntimeError"}}}}'", stack: "Error: Error: [ethjs-query] while formatting outpu…/task_queues.js:93:5)","name":"RuntimeError"}}}}'"}
createItem @ main.js:177
async function (async)
createItem @ main.js:146

Hey Keith, I hope you are well!

Can you please provide the contract?

/Capplequoppe

Hey Capplequoppe, not bad thanks and hope all is good your end.

Appreciate you having a look: Wasn’t sure if you wanted anything in specific so have copied index and main below. On a side note guys @Capplequoppe, @filip, @ivan i’m loving all your videos on Moralis and learning a lot (not fast enough :slight_smile:) and I think a Moralis course would get a lot of interest in the academy. Just a thought.

<!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">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
    <link rel="stylesheet" href="main.css">
    <title>Showcase NFT </title>
</head>
<body class="bg-dark">

    <nav class="navbar navbar-expand-lg navbar-dark bg-transparent border-bottom border-light">
        <a class="navbar-brand btn btn-outline-moralis"  href="#">Showcase NFT</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <form class="mx-2 d-inline flex-md-fill">
                <input type="search" class="bg-transparent border-light form-control text-light mr-sm-2 rounded-pill" placeholder="Search by item or creator">
            </form>
          <ul class="navbar-nav mr-auto">
            <li class="nav-item">
              <a class="nav-link" id="btnMyItems" href="#">My items</a>
            </li>
          </ul>
          <div class="d-flex">
            <button class="btn btn-primary rounded-pill my-2 my-sm-0 mr-md-2" id="btnOpenCreateItem">Create Your Own NFT</button>
            <button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0 " id="btnConnect">Connect wallet</button>
            <button class="btn btn-outline-moralis rounded-pill my-2 my-sm-0" id="btnUserInfo">Profile</button>
          
        </div>
        </div>
      </nav>

    <div class="container">
        <div class="row row-cols-1 row-cols-md-4 mt-5" id="itemsForSale">

        </div>
    </div>
  


    <div class="col mb-4" id="marketplaceItemTemplate">
        <div class="card h-100 border-light bg-transparent text-light">
            <nav class="card-header navbar navbar-dark text-light p-1">
                <img width="30" height="30" class="d-inline-block align-top rounded-circle" src="" alt="">
                <span></span>
            </nav>
         
            <img src="..." class="card-img-top" alt="...">
            <div class="card-body d-flex align-items-end">
                <div class="w-100">
                    <h5 class="card-title"></h5>
                    <p class="card-text"></p>
                    <button class="btn btn-primary btn-block"></button>
                </div>
        
            </div>
          </div>
    </div>

    <div class="col mb-4" id="itemTemplate">
        <div class="card h-100 border-light bg-transparent text-light">
            <img src="..." class="card-img-top" alt="...">
            <div class="card-body d-flex align-items-end">
                <div class="w-100">
                    <h5 class="card-title"></h5>
                    <p class="card-text"></p>

                    <div class="input-group mb-3">
                        <input type="number" min="1" step="1" class="form-control" placeholder="Price">
                        <div class="input-group-append">
                          <button class="btn btn-outline-secondary" type="button">Put for sale</button>
                        </div>
                      </div>
                </div>
        
            </div>
          </div>
    </div>

    <!-- Modal -->
    <div class="modal fade" id="userInfo" tabindex="-1">
        <div class="modal-dialog">
        <div class="modal-content bg-dark text-light">
            <div class="modal-header">
            <h5 class="modal-title" >User Profile</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
            </div>
            <div class="modal-body">

                <div class="form-group">
                    <label for="txtUsername">Username</label>
                    <input type="text" class="form-control" id="txtUsername" required placeholder="Enter username">
                </div>

                <div class="form-group">
                    <label for="txtEmail">Email address</label>
                    <input type="email" class="form-control" id="txtEmail" aria-describedby="emailHelp" placeholder="Enter email">
                    <small id="emailHelp" class="form-text text-muted">Optional</small>
                </div>
        
                <img width="50" height="50" src="" id="imgAvatar" alt="">

                <div class="form-group">
                    <label for="fileAvatar">Select Avatar</label>
                    <input type="file" class="form-control-file" id="fileAvatar">
                </div>
            </div>
            <div class="modal-footer">
            <button type="button" id="btnLogout" class="btn btn-secondary" data-dismiss="modal">Log out</button>
            <button type="button" id="btnCloseUserInfo" class="btn btn-secondary" data-dismiss="modal">Close</button>
            <button type="button" id="btnSaveUserInfo" class="btn btn-primary">Save</button>
            </div>
        </div>
        </div>
    </div>


        <!-- Modal -->
        <div class="modal fade" id="createItem" tabindex="-1">
            <div class="modal-dialog">
            <div class="modal-content bg-dark text-light">
                <div class="modal-header">
                <h5 class="modal-title" >Create Item</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body">
    
                    <div class="form-group">
                        <label for="txtUsername">Name</label>
                        <input type="text" class="form-control" id="txtCreateItemName" required placeholder="Enter name">
                    </div>
    
                    <div class="form-group">
                        <label for="txtCreateItemDescription">Description</label>
                        <textarea class="form-control" id="txtCreateItemDescription"  cols="30" rows="5" placeholder="Enter description"></textarea>
                    </div>
                    <div class="form-group">
                        <label for="txtUsername">Price</label>
                        <input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required class="form-control">
                    </div>

                    <div class="form-group">
                        <label for="selectCreateItemStatus">Status</label>
                        <select class="form-control" id="selectCreateItemStatus">        
                            <option value="0">Showcase Only</option>
                            <option value="1">Instant buy</option>
                            <option value="2">Accept Offers</option>
                        </select>
                    </div>

                    <div class="form-group">
                        <label for="fileCreateItemFile">Select file</label>
                        <input type="file" class="form-control-file" id="fileCreateItemFile">
                    </div>
                </div>
                <div class="modal-footer">
                <button type="button" id="btnCloseCreateItem" class="btn btn-secondary" data-dismiss="modal">Close</button>
                <button type="button" id="btnCreateItem" class="btn btn-primary">Create!</button>
                </div>
            </div>
            </div>
        </div>

        
        <!-- Modal -->
        <div class="modal fade" id="userItems" tabindex="-1">
            <div class="modal-dialog modal-xl">
            <div class="modal-content bg-dark text-light">
                <div class="modal-header">
                <h5 class="modal-title" >My Items</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                </div>
                <div class="modal-body row row-cols-1 row-cols-md-4 mt-5" id="userItemsList">
    
                </div>
                <div class="modal-footer">
                    <button type="button" id="btnCloseUserItems" class="btn btn-secondary" data-dismiss="modal">Close</button>
                </div>
            </div>
            </div>
        </div>



    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script>
    <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>
Moralis.initialize("sy7cr1ZZt64tfn9huIr5QHP5sikUyBNxBuJygbtx");
Moralis.serverURL = 'https://snpebh67zxfb.moralis.io:2053/server'
const TOKEN_CONTRACT_ADDRESS = "0x817d8454559ed206Caa869Fef0F22dEA87CA56D0";
const MARKETPLACE_CONTRACT_ADDRESS = "0x1d6A4CF64B52F6c73f201839AdED7379Ce58059c";

init = async () => {
    hideElement(userItemsSection);
    window.web3 = await Moralis.Web3.enable();
    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
    window.marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);
    initUser();
    loadItems();

    const soldItemsQuery = new Moralis.Query('SoldItems');
    const soldItemsSubscription = await soldItemsQuery.subscribe();
    soldItemsSubscription.on("create", onItemSold);

    const itemsAddedQuery = new Moralis.Query('ItemsForSale');
    const itemsAddedSubscription = await itemsAddedQuery.subscribe();
    itemsAddedSubscription.on("create", onItemAdded);
}

onItemSold = async (item) => {
    const listing = document.getElementById(`item-${item.attributes.uid}`);
    if (listing){
        listing.parentNode.removeChild(listing);
    }
    
    user = await Moralis.User.current();
    if (user){
        const params = {uid: `${item.attributes.uid}`};
        const soldItem = await Moralis.Cloud.run('getItem', params);
        if (soldItem){
            if (user.get('accounts').includes(item.attributes.buyer)){
                getAndRenderItemData(soldItem, renderUserItem);
            }

            const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
            if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
          
        }
   
    }
}

onItemAdded = async (item) => {
    const params = {uid: `${item.attributes.uid}`};
    const addedItem = await Moralis.Cloud.run('getItem', params);
    if (addedItem){
        user = await Moralis.User.current();
        if (user){
            if (user.get('accounts').includes(addedItem.ownerOf)){
                const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
                if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);

                getAndRenderItemData(addedItem, renderUserItem);
                return;
            }
        }
        getAndRenderItemData(addedItem, renderItem);
    }

}

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

login = async () => {
    try {
        await Moralis.Web3.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 = "";
        }

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

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

        $('#userInfo').modal('show');
    }else{
        login();
    }
}

saveUserInfo = async () => {
    user.set('email', userEmailField.value);
    user.set('username', userUsernameField.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;
    }

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

    const nftFilePath = nftFile.ipfs();

    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 nftId = await mintNft(nftFileMetadataFilePath);

    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');

    switch(createItemStatusField.value){
        case "0":
            return;
        case "1":
            await ensureMarketplaceIsApproved(nftId, TOKEN_CONTRACT_ADDRESS);
            await marketplaceContract.methods.addItemToMarket(nftId, TOKEN_CONTRACT_ADDRESS, createItemPriceField.value).send({from: userAddress });
            break;
        case "2":
            alert("Not yet supported!");
            return;
    }
}

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

openUserItems = async () => {
    user = await Moralis.User.current();
    if (user){    
        $('#userItems').modal('show');
    }else{
        login();
    }
}

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    ownedItems.forEach(item => {
        const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
        if (userItemListing) return;
        getAndRenderItemData(item, renderUserItem);
    });
}

loadItems = async () => {
    const items = await Moralis.Cloud.run("getItems");
    user = await Moralis.User.current();
    items.forEach(item => {
        if (user){
            if (user.attributes.accounts.includes(item.ownerOf)){
                const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
                if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
                getAndRenderItemData(item, renderUserItem);
                return;
            }
        }
        getAndRenderItemData(item, renderItem);
    });
}


initTemplate = (id) => {
    const template = document.getElementById(id);
    template.id = "";
    template.parentNode.removeChild(template);
    return template;
}

renderUserItem = async (item) => {
    const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
    if (userItemListing) return;

    const userItem = userItemTemplate.cloneNode(true);
    userItem.getElementsByTagName("img")[0].src = item.image;
    userItem.getElementsByTagName("img")[0].alt = item.name;
    userItem.getElementsByTagName("h5")[0].innerText = item.name;
    userItem.getElementsByTagName("p")[0].innerText = item.description;

    userItem.getElementsByTagName("input")[0].value = item.askingPrice ?? 1;
    userItem.getElementsByTagName("input")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].onclick = async () => {
        user = await Moralis.User.current();
        if (!user){
            login();
            return;
        }
        await ensureMarketplaceIsApproved(item.tokenId, item.tokenAddress);
        await marketplaceContract.methods.addItemToMarket(item.tokenId, item.tokenAddress, userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') });
    };

    userItem.id = `user-item-${item.tokenObjectId}`
    userItems.appendChild(userItem);
}

renderItem = (item) => {
    const itemForSale = marketplaceItemTemplate.cloneNode(true);
    if (item.sellerAvatar){
        itemForSale.getElementsByTagName("img")[0].src = item.sellerAvatar.url();
        itemForSale.getElementsByTagName("img")[0].alt = item.sellerUsername;
     
    }

    itemForSale.getElementsByTagName("img")[1].src = item.image;
    itemForSale.getElementsByTagName("img")[1].alt = item.name;
    itemForSale.getElementsByTagName("h5")[0].innerText = item.name;
    itemForSale.getElementsByTagName("p")[0].innerText = item.description;

    itemForSale.getElementsByTagName("button")[0].innerText = `Buy for ${item.askingPrice}`;
    itemForSale.getElementsByTagName("button")[0].onclick = () => buyItem(item);
    itemForSale.id = `item-${item.uid}`;
    itemsForSale.appendChild(itemForSale);
}


getAndRenderItemData = (item, renderFunction) => {
    
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data => {
        item.name = data.name;
        item.description = data.description;
        item.image = data.image;
        renderFunction(item);
    })
}

ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');
    const contract = new web3.eth.Contract(tokenContractAbi, tokenAddress);
    const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
    if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS){
        await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS,tokenId).send({from: userAddress});
    }
}

buyItem = async (item) => {
    user = await Moralis.User.current();
    if (!user){
        login();
        return;
    } 
    await marketplaceContract.methods.buyItem(item.uid).send({from: user.get('ethAddress'), value: item.askingPrice});
}

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

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

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

const openCreateItemButton = document.getElementById("btnOpenCreateItem");
openCreateItemButton.onclick = () => $('#createItem').modal('show');

//  User profile
const userInfo = document.getElementById("userInfo");
const userUsernameField = 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;

// Item creation
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");
document.getElementById("btnCloseCreateItem").onclick = () => hideElement(createItemForm);
document.getElementById("btnCreateItem").onclick = createItem;

// User items
const userItemsSection = document.getElementById("userItems");
const userItems = document.getElementById("userItemsList");
document.getElementById("btnCloseUserItems").onclick = () => hideElement(userItemsSection);
const openUserItemsButton = document.getElementById("btnMyItems");
openUserItemsButton.onclick = openUserItems;


const userItemTemplate = initTemplate("itemTemplate");
const marketplaceItemTemplate = initTemplate("marketplaceItemTemplate");

// Items for sale
const itemsForSale = document.getElementById("itemsForSale");


init();

Thankyou very much as always

Thanks!

What I was looking for was the smart contract.
Can you post that one too?

/Capplequoppe

Apologies, I think this is what your after, forgive me still a novice

pragma solidity >=0.4.22 <0.9.0;

contract Migrations {
  address public owner = msg.sender;
  uint public last_completed_migration;

  modifier restricted() {
    require(
      msg.sender == owner,
      "This function is restricted to the contract's owner"
    );
    _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }
}

token contract

`pragma solidity ^0.8.0;

import "../node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "../node_modules/@openzeppelin/contracts/utils/Counters.sol";

contract ShowcaseNFTtoken is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor () ERC721 ("ShowcaseNFTtoken", "SHNFT") {}

    struct Item {
        unint 256 id;
        address creator;
        string uri;
    }

    mapping (uint256 => Item) public Items;

    function createItem (string memory uri) public returns (uint256){
        _tokenIds.increment ();
        uint256 newItemId = _tokenIds.current ();
        _safeMint (msg.sender, newItemId);

        Items [newItemId] = Item (newItemId, msg.sender, uri);

        return newItemId;
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        return Items [tokenId].uri;
    }

}

`
``` If it's not this just let me know. Thanks again

From what I can see here, you seem to have a spelling mistake when you declare the Id of the Item.

should be uint256 instead of unint 256.

If this does not work let me know.
Rememver also to update the address in your javascript file so that it points to the new contract address after you call

truffle migrate --reset

/Capplequoppe

I’ll give it a try thanks for your help

1 Like

Hi guys, when trying to connect wallet, metamask comes up but I get the following error:

ParseError: 100 XMLHttpRequest failed: "Unable to connect to the Parse API"

Can anyone help?

Did it work previously?
If so what has changed since then?
Is the code up to date that is pasted above?