Items for sale on Morarible NFT marketplace

Hey guys
Iā€™m doing part 11 of the Morarible NFT marketplace and Iā€™m getting this error when I try to create a NFT for sale on my marketplace.
Cheers

setting a price for nft for selling on marketplace

Could you share how you are calling it?

HTML

!DOCTYPE html>

<html lang="en">

<head>

    <link rel="shortcut icon" href="">

    <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>

    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">

    <link rel="stylesheet" href="main.css">

 

</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="#">Morarable</a>

          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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</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>

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

 </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>

    <div id="userItems">

      <h4>My Items</h4>

      <div id="userItemsList"></div>

      <button id="btnCloseUserItems">Close</button>

    </div>

    <div id="itemTemplate">

      <img src="" alt="">

      <h5></h5>

      <p></p>

    </div>

       

    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

    <script src="https://unpkg.com/moralis@latest/dist/moralis.js"></script>

    <script src="main.js"></script>

    <script src="abi.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>

</body>

</html>

Javascript

const serverUrl = "https://vxnx9mu8hh9u.usemoralis.com:2053/server";

const appId = "z75nQcm3wcoe9xd9MK8c6Lye9akXiMw1QldhfvE6";

const TOKEN_CONTRACT_ADDRESS = "0x99495223da7dFE1A14d5224Bc90bad4a01F0e58A";

const MARKETPLACE_CONTRACT_ADDRESS = "0xb94bb1b53ab68465cEB10b89E3B67Eae2Db003BA";

Moralis.start({ serverUrl, appId });

init = async () => {

    hideElement(userItemsSection);

    hideElement(userInfo);

    hideElement(createItemForm);

    await Moralis.enableWeb3();

    web3 = new Web3(Moralis.provider);

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

    marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);

        initUser();

        loadUserItems();

           

}

initUser = async () => {

    if (await Moralis.User.current()){

        hideElement(userConnectButton);

        showElement(userProfileButton);

        showElement(openCreateItemButton);

        showElement(openUserItemsButton);

        loadItems();

    }else{

        showElement(userConnectButton);

        hideElement(userProfileButton);

        hideElement(openCreateItemButton);

        hideElement(createItemForm);

        hideElement(openUserItemsButton);

    }

}

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();

}

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);

    }

}

loadUserItems = async () => {

    const params =  { token_address: TOKEN_CONTRACT_ADDRESS };

    const ownedItems = await Moralis.Cloud.run("getUserItems", params);

    ownedItems.forEach(item => {

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

        if (userItemListing) return;

        getAndRenderItemData(item, renderUserItem);

    });

}

loadItems = async () => {

    const params =  { token_address: TOKEN_CONTRACT_ADDRESS };

    const items = await Moralis.Cloud.run("getItems", params);

    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);

    });

}

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 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();

console.log(item);

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(item.tokenId, item.tokenAddress, userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') });

    case "2":

        alert("not yet supported");

        return;

}

}

initTemplate = (id) => {

    const template = document.getElementById(id);

    template.id = "";

    template.parentNode.removeChild(template);

    return template;

}

renderUserItem = (item) => {

    const userItem = userItemTemplate.cloneNode(true);

    userItem.getElementsByTagName("img")[0].src = item.image;

    userItem.getElementsByTagName("img")[0].alt = item.name;

    userItem.getElementsByTagName("p")[0].innerText = item.name;

    userItem.getElementsByTagName("p")[0].innerText = item.description;

    userItems.appendChild(userItem);

    userItems.id = `user-item-${item.tokenObjectId}`

    userItems.appendChild(userItem);

    console.log(userItems);

}

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("span")[0].innerText = item.sellerUsername;

    }

    itemForSale.getElementsByTagName("img")[0].src = item.image;

    itemForSale.getElementsByTagName("img")[0].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);

    })

}

mintNFT = async (metadataUri) => {

    const receipt = await tokenContract.methods.createItem(metadataUri).send({from: ethereum.selectedAddress});;

    console.log(receipt);

    return receipt.events.Transfer.returnValues.tokenId;

}

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});

    }

}

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

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

openUserItems = async () => {

    user = await Moralis.User.current();

    if (user){    

        showElement(userItemsSection);

    }else{

        login();

    }

}

//Navbar

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

userConnectButton.onclick = login;

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

userProfileButton.onclick = openUserInfo;

//Userinfo

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;

//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");

const openCreateItemButton = document.getElementById("btnOpenCreateItem");

openCreateItemButton.onclick = () => showElement(createItemForm);

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");

init();

cloud function

Moralis.Cloud.define("getUserItems", async (request) => {

  const options = { address: request.params.token_address, chain: "ropsten" };

  const NFTowners = await Moralis.Web3API.token.getNFTOwners(options);

  const queryResults = NFTowners.result.filter(x => x.owner_of == request.user.attributes.accounts);

const results = [];

 for (let i = 0; i < queryResults.length; ++i) {

  results.push({

    "tokenObjectId": queryResults[i].id,

    "tokenid": queryResults[i].token_id,

    "tokenAddress": queryResults[i].token_address,

    "symbol": queryResults[i].symbol,

    "tokenUri": queryResults[i].token_uri,

  });

}

return results;

});

  Moralis.Cloud.define("getItems", async (request) => {

     

    const query = new Moralis.Query("ItemsForSale");

    query.notEqualTo("isSold", true);

    query.select("uid","askingPrice","tokenAddress","tokenId", "token.token_uri", "token.symbol","token.owner_of","token.id", "user.avatar","user.username");

 

    const queryResults = await query.find({useMasterKey:true});

    const results = [];

 

    for (let i = 0; i < queryResults.length; ++i) {

 

      if (!queryResults[i].attributes.token || !queryResults[i].attributes.user) continue;

 

      results.push({

        "uid": queryResults[i].attributes.uid,

        "tokenId": queryResults[i].attributes.tokenId,

        "tokenAddress": queryResults[i].attributes.tokenAddress,

        "askingPrice": queryResults[i].attributes.askingPrice,

 

        "symbol": queryResults[i].attributes.token.attributes.symbol,

        "tokenUri": queryResults[i].attributes.token.attributes.token_uri,

        "ownerOf": queryResults[i].attributes.token.attributes.owner_of,

        "tokenObjectId": queryResults[i].attributes.token.id,

       

        "sellerUsername": queryResults[i].attributes.user.attributes.username,

        "sellerAvatar": queryResults[i].attributes.user.attributes.avatar,

      });

    }

 

    return results;

  });

  Moralis.Cloud.beforeSave("ItemsForSale", async (request) => {

 

    const options = { address: "0x6861932B8931c656ea7891fD7aC2c4ad1d4df1ee", chain: "ropsten" };

    const NFTowners = await Moralis.Web3API.token.getNFTOwners(options);

    const queryResults = NFTowners.result.filter(x => x.token_address == request.object.get('tokenAddress') && x.token_id == request.object.get('tokenId'));

    query.equalTo("token_address", request.object.get('tokenAddress'));

    query.equalTo("token_id", request.object.get('tokenId'));

    const object = queryResults[0];

    if (object){

      const owner = object.owner_of;

        const userQuery = new Moralis.Query(Moralis.User);

        userQuery.equalTo("accounts", owner);

        const userObject = await userQuery.first({useMasterKey:true});

        if (userObject){

            request.object.set('user', userObject);

        }

        request.object.set('token', object);

    }

  });

Moralis.Cloud.beforeSave("SoldItems", async (request) => {

 

    const query = new Moralis.Query("ItemsForSale");

    query.equalTo("uid", request.object.get('uid'));

    const item = await query.first();

    if (item){

      request.object.set('item', item);

      item.set('isSold', true);

      await item.save();

         

      const userQuery = new Moralis.Query(Moralis.User);

        userQuery.equalTo("accounts", request.object.get('buyer'));

      const userObject = await userQuery.first({useMasterKey:true});

      if (userObject){

          request.object.set('user', userObject);

      }

    }

  });

Is that the entire error?

yes that is the entire error.
Cheers :slight_smile:

What do you actually do in your app to get this ā€œfromā€ address error? Is it from calling a cloud function or running a function from main.js?

Its a function in the main.js. Iā€™m trying list a NFT to the market place.

What is the actual function? Can you add more details please. There is a lot of code in main.js. Check the parameters you are using to see where this missing from address could be.

1 Like

Hi Glad
Iā€™ve been doing some trial and error and Iā€™m struggling to define userItem. Iā€™ve been on GitHub looking at the repository and I cant seem to find where I have gone wrong.
Thanks in advance.

Screenshot 2022  user item is not defined

How do you get to this error (steps to replicate it from your projectā€™s code)?

Just looking through your main.js, the issue looks to be at this line

userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') })

userItem doesnā€™t seem to be defined anywhere in the createItem function.

1 Like

Yes thatā€™s the line of code where my error is. Iā€™ve tried defining userItem in my createItem function but I end up getting more errors when I try. I must not be defining it correctly.

You can check the final main.js, that await marketplaceContract.methods.addItemToMarket line is used in the renderUserItem function, not the createItem function as youā€™re trying.

Hi Glad
Iā€™ve done as you recommended but my app ends up not working at all. I think that repository might be outdated.
Cheers :slight_smile:

This issue is less to do with the repo being outdated but more a general programming principle - you canā€™t use the userItem variable if it hasnā€™t been created anywhere like at const userItem = userItemTemplate.cloneNode(true);.

If youā€™re making changes or doing things differently, you will have to account for this - you canā€™t just copy code elsewhere if it relies on other code.

Hi Glad
yes Iā€™m aware it is a general programming principle.
Iā€™ve been trying to define userItem but my app always stops working and then I get alot of errors in the console.
Ill keep trying to solve this issue.
Thank you for all your help.
Cheers :slight_smile: