Stuck on this ERROR when i click on the button to resell NFt's , i'm following CLoning RARIBLE

here’s my error

Here’s my cloud function

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

  const query = new Moralis.Query("EthNFTOwners");
  query.equalTo("contract_type", "ERC721");
    query.containedIn("owner_of", request.user.attributes.accounts);
  const queryResults = await query.find();
  const results = [];
  for (let i = 0; i < queryResults.length; ++i) {
    results.push({
      
      "tokenObjectId": queryResults[i].id,
       "tokenid": queryResults[i].attributes.token_id,
       "tokenAddress": queryResults[i].attributes.token_address,
       "symbol": queryResults[i].attributes.symbol,
       "tokenUri": queryResults[i].attributes.token_uri,
    });
  }
  return results;
});

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

  const query = new Moralis.Query("EthNFTOwners");
  query.equalTo("token_address", request.object.get('tokenAddress'));
   query.equalTo("token_id", request.object.get('tokenId'));
  const object = await query.first();
  if(object){
  const owner = object.attributes.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);
     } 
  }
  
});

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

  const query = new Moralis.Query("itemsForSale");
  query.notEqualTo("isSold", true);
  
  query.select("uid", "tokenAddress", "tokenId", "askingPrice", "token.token_uri", "token.symbol", "token.owner_of","token.id", "user.username","user.avatar");
  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.token_id,
       "tokenAddress": queryResults[i].attributes.token_address,
        "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.define("getItem", async (request) => {

  const query = new Moralis.Query("itemsForSale");
  query.equalTo("uid", request.params.uid);
  
  query.select("uid", "tokenAddress", "tokenId", "askingPrice", "token.token_uri", "token.symbol", "token.owner_of","token.id", "user.username","user.avatar");
  const queryResult = await query.first({useMasterKey: true});
  if(!queryResult)return;
 return {
      "uid": queryResult.attributes.uid,
       "tokenId": queryResult.attributes.token_id,
       "tokenAddress": queryResult.attributes.token_address,
        "askingPrice": queryResult.attributes.askingPrice,
      
       "symbol": queryResult.attributes.token.attributes.symbol,
       "tokenUri": queryResult.attributes.token.attributes.token_uri,
      "ownerOf": queryResult.attributes.token.attributes.owner_of,
       "tokenObjectId": queryResult.attributes.token.id,
   
      "sellerUsername": queryResult.attributes.user.attributes.username,
      "sellerAvatar": queryResult.attributes.user.attributes.avatar,
    };
});

Here’s my main.js

Moralis.initialize("ujvcezKVDZh4LKebB0EEsBMzO4Ac0BJIjEYQR7Ix");
Moralis.serverURL = 'https://lbgxuu4enm7h.bigmoralis.com:2053/server'
const TOKEN_CONTRACT_ADDRESS = "0x397Ec0554F9B05128bb133946e28e2Cea46a4663";
const MARKETPLACE_CONTRACT_ADDRESS = "0x53Edc2F72324f314d7FBaD87c27643A435de95d4";



init = async () => {
    hideElement(userItemsSection);
    hideElement(userInfo);
    hideElement(createItemForm);
    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);
        }

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

openUserItems = async () => {
    user = await Moralis.User.current();
    if (user) {
        

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



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

    if (userAvatarFile.files.length > 0) {
        const avatar = new Moralis.File("avatar.png", 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 provide a name!")
           return;

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

    const nftFilePath = nftFile.ipfs();
    //CAN REMOVE THIS

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

    //CAN REMOVE THIS

    

    const nftId = await mintNft(nftFileMetadataFilePath);

    //USELESS CODE

    /// END HERE

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

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.avatar){
        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)=> {
   const  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";

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

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

const openCreateItemButton = document.getElementById("btnOpenCreateItem");
openCreateItemButton.onclick = () => showElement(createItemForm);

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

Here’s my index.html file

<!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>MarketPlace</title>
    
</head>
<body>
    <div>
        <button id="btnConnect">Connect Wallet</button>
        <button id="btnUserInfo">Profile</button>
        <button id="btnOpenCreateItem">CreateItem</button>
        <button id="btnMyItems">My Items</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>
    <div id="userItems">
        <h4> My items</h4>

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

    </div>

    <div id="itemsForSale"></div>

    <div id="itemTemplate">
       <img src="" alt="">
       <h5></h5>
       <p></p>
       <input type="number" min="1" step="1">
        <button> Put for sale </button>

    </div>

    <div id="marketplaceItemTemplate">
        <img src="" alt="">
        <h6></h6>
        <img src="" alt="">
        <h5></h5>
        <p></p>
        <button></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>

here’s my error

Hi,

Please could you refer to this post for basic errors - Solving common problems [Rarible Clone]

Also, make sure to use Diff checker to see if there are any changes from your code to the original code over here - https://github.com/MoralisWeb3/youtube-tutorials/tree/main/rarible-clone.

it looks like the error is generated from this line:

    const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});

You could use console log to print those parameters before calling that method, to see if everything looks ok.

Thing is that function works just fine when i create an item, i only get this issue when i try to resell after creation

Just gone through the diff checker, code seems consistent. The issue appears only when i try to resll an item. Once i click the put on sale button, i get that error

You could try to debug it, to use console.log before the code that you think that generates that error.

what would that look like , console.log(userItem.getElementsByTagName(ā€œbuttonā€)[0].onclick) ?

No,
I mean something like if you want to see what happens before calling contract.methods.getApproved to do something like this by adding some console.log lines before that function:

console.log(tokenId);
console.log(userAddress);
 const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});

Tried that still no luck. Also used diff checker to compare my code to the final one, gone over the tutorial video a couple of times to check for error but still can’t find one. Can create and send items to market so the function works well. the only issue is trying to resell from my items

after you added those lines:

console.log(tokenId);
console.log(userAddress);

what did you see on console before the error?

when i use(
console.log(tokenId);
console.log(userAddress);
)
here’s what i get

and when i use
console.log(item.tokenId);
console.log(item.tokenAddressAddress);

it says undefined

1 Like

That is the function where you should add those two console.log lines after userAddress is initialised.

1 Like

It just returns the same error, i think the ensureMarketplaceisApproved function is fine, the issues has to be with the put on sale button not recognizing the item token id.

it doesn’t even get to the ensureMarketplaceisApproved function.

Bear in mind i can still create items and the go on the market but when a user buys, the user can’t put it back on sale

That may be the case of not properly setting tokenId, but still a console log should show if that is the case by displaying what is the value of tokenId, be it undefined or something else

I think it gets the error before it even gets to the EnsureMarket function

it looks like this is the function that displays an item:

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

and it adds that .onclick async function:

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

and it looks like it gives an error on this call:

await ensureMarketplaceIsApproved(item.tokenId, item.tokenAddress);

and this is the ensureMarketpalceIsApproved function:

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

What are your assumptions when you say that it doesn’t make it to this EnsureMarket function?

cause when i console log the Item.tokenId and item.tokenAddress i get undefined

where did you put those console.log for the Item.tokenId and item.tokenAddress?
you can also put a console.log(ā€œin ensureMarketplaceIsApprovedā€) as a first line of that function to know if it makes it there or not.

I just copied all the code from the final version and applied it, works fine now, don’t know what i got wrong but just gonna build on the final version. Thanks for your help mate