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