Finding EthTokenBalance -- I CLONED RARIBLE IN 24H - Cloud functions [PART 8]

i used this in loadUserItems:

    const options = {
        chain: "eth",
        address: request.user.attributes.ethAddress,
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options); 

I used it to replace console.log(ownedItems);
this is what you previously told me to put in.

loadUserItems = async () => {

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

    console.log(ownedItems);  

    ownedItems.forEach(item => {

    getAndRenderItemData(item, renderUserItem);

    })

}

so this would be the result:

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    const options = {
        chain: "eth",
        address: request.user.attributes.ethAddress,
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options); 
    ownedItems.forEach(item => {
    getAndRenderItemData(item, renderUserItem);
    })
}

Comes back with this error:
Screenshot 2022-07-01 153500

this is my entire JS if it helps bette runderstand:


const serverUrl = "https://#######.usemoralis.com:2053/server";
const appId = "######################################";
const TOKEN_CONTRACT_ADDRESS = "0x904fE54f1b5Eaa1621B31B05642EDd1fb43555F5"
Moralis.start({ serverUrl, appId, TOKEN_CONTRACT_ADDRESS });

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

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

initUser = async () => {
    if (await Moralis.User.current()){
        hideElement(firstTip);
        showElement(secondTip);
        hideElement(userConnectButton);
        showElement(userProfileButton);
        showElement(openCreateItemButton);
        showElement(openUserItemsButton);
        loadUserItems();
    }else{
        showElement(firstTip);
        hideElement(secondTip);
        showElement(userConnectButton);
        hideElement(userProfileButton);
        hideElement(openCreateItemButton);
        hideElement(createItemForm);
        hideElement(openUserItemsButton);
    }
}
login = async () => {
    try {
        await Moralis.authenticate();
        initUser();
    } catch (error) {
        if (error.code == '4001'){
            alert(error.code + ": To connect your wallet to this site, you must confirm sign.");
        }
    }
}

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

checkSaveUserInfo = async () => {
    if (userNameField.value.length ==0 && userEmailField.value.length ==0){
        alert("Please supply a name and email.");
        return;
    }else if (userEmailField.value.length ==0){
            alert("Please supply an email.");
            return;
    }else if (userNameField.value.length ==0){
            alert("Please supply a name.");
            return;
        }
    else{
        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);
    }
try{
    await user.save();
}
 catch(error) {
    console.log(error);
    alert("That email already exists. Please choose another.");
    document.getElementById('txtEmail').value = '';
    return;
   }
    alert("User info saved successfully!");
    openUserInfo();
}

openUserItems = async () => {   
      user = await Moralis.User.current();
    if(user){
        showElement(userItemsSection);
    }else{
        login();
    }
}

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    const options = {
        chain: "eth",
        address: request.user.attributes.ethAddress,
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options); 
    ownedItems.forEach(item => {
    getAndRenderItemData(item, renderUserItem);
    })
}

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].src = item.name;
    userItem.getElementsByTagName("h5")[0].innerText = item.name;
    userItem.getElementsByTagName("p")[0].innerText = item.description;
    userItems.appendChild(userItem);
}

getAndRenderItemData = (item, renderFunction) =>{
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data =>{
        data.symbol = item.symbol;
        data.tokenId = item.tokenId;
        data.tokenAddress = item.tokenAddress;
        renderFunction(data);
    })
}

createItem = async () => {
    if (createItemFile.files.length == 0){
        alert("Please select a file!");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please give the item a name!");
        return;
    }
    mintNft = async (metadataUri) => {
        const receipt = await tokenContract.methods.createItem(metadataUri).send({ from: ethereum.selectedAddress });
        console.log(receipt);
        return receipt.events.Transfer.returnValues.tokenId;
    }

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

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

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

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

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

const nftId = await mintNft(nftFileMetadataFilePath);


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

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

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

const firstTip = document.getElementById("tipConnect1");
const secondTip = document.getElementById("tipConnect2");

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

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

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

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

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

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

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

i could have also done it like this that doesnt display errors but still doesnt show the NFTs in the tab.

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    // const user = Moralis.User.current();
    // const ownedItems = await Moralis.Web3API.account.getNFTs({
    //   chain: "eth",
    //   address: user.attributes.ethAddress,
    // });
  
    ownedItems.forEach((item) => {
      getAndRenderItemData(item, renderUserItem);
    });
  };

Use the below code to get nfts. and I think you are confused between the code to get erc20 token balances and NFT balance.
getUserItems cloud code only gets the erc20 token balances, not the NFT balance.

const options = {
        chain: "eth",
        address: Moralis.User.current().get("ethAddress"), //request works in cloud functions only.
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options);

is this correct implementation?

loadUserItems = async () => {
    const user = Moralis.User.current();
    const options = {
        chain: "eth",
        address: Moralis.User.current().get("ethAddress"), 
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options);
  
    ownedItems.forEach((item) => {
      getAndRenderItemData(item, renderUserItem);
    });
  };

Is ownedItems defined anywhere in the code? or should it be replaced with polygonNFTs

Yeah i changed that now.
Its only has this error now:

remove the request.user.attributes.ethAddress as this only works on cloud code and replace it with Moralis.User.current().get("ethAddress") to the user eth address.

I seem to be getting an uncaught TypeError on load (polygonNFTs.forEach is not a function at loadUserItems).

loadUserItems = async () => {
    const user = Moralis.User.current();
    const options = {
        chain: "eth",
        address: Moralis.User.current().get("ethAddress"), 
      };
      const polygonNFTs = await Moralis.Web3API.account.getNFTs(options);
  
      polygonNFTs.forEach((item) => {
      getAndRenderItemData(item, renderUserItem);
    });
  };

forEach needs to be run on an array so you need to target the NFT array inside the polygonNFTs object.

polygonNFTs.result.forEach((item) => {
  ...

I have decided to change to TestNet to remove some other errors. Im now using Ropsten with Infura.
There dont seem to be any errors logged. I was able to get EthNFTTransfers class and EthTransactions that i didnt have before. I am missing EthNTFOwner.

In regard to displaying NFTs that ive uploaded to the db, can i still use this cloud function?

I cant seem to find any particular issues with my JS but maybe i am just configuring it wrong.



const serverUrl = "https://hiee58acp8ql.usemoralis.com:2053/server";
const appId = "OE9Y4yDag3sCz0ECOtvje95DGZqbhPR2C3zTYjsr";
const TOKEN_CONTRACT_ADDRESS = "0x0dE601E38e2282AEDE397BF5c16B819000961301"
Moralis.start({ serverUrl, appId, TOKEN_CONTRACT_ADDRESS });

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

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

initUser = async () => {
    if (await Moralis.User.current()){
        hideElement(firstTip);
        showElement(secondTip);
        hideElement(userConnectButton);
        showElement(userProfileButton);
        showElement(openCreateItemButton);
        showElement(openUserItemsButton);
        loadUserItems();
    }else{
        showElement(firstTip);
        hideElement(secondTip);
        showElement(userConnectButton);
        hideElement(userProfileButton);
        hideElement(openCreateItemButton);
        hideElement(createItemForm);
        hideElement(openUserItemsButton);
    }
}
login = async () => {
    try {
        await Moralis.authenticate();
        initUser();
    } catch (error) {
        if (error.code == '4001'){
            alert(error.code + ": To connect your wallet to this site, you must confirm sign.");
        }
    }
}

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

checkSaveUserInfo = async () => {
    if (userNameField.value.length ==0 && userEmailField.value.length ==0){
        alert("Please supply a name and email.");
        return;
    }else if (userEmailField.value.length ==0){
            alert("Please supply an email.");
            return;
    }else if (userNameField.value.length ==0){
            alert("Please supply a name.");
            return;
        }
    else{
        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);
    }
try{
    await user.save();
}
 catch(error) {
    console.log(error);
    alert("That email already exists. Please choose another.");
    document.getElementById('txtEmail').value = '';
    return;
   }
    alert("User info saved successfully!");
    openUserInfo();
}

openUserItems = async () => {   
      user = await Moralis.User.current();
    if(user){
        showElement(userItemsSection);
    }else{
        login();
    }
}

loadUserItems = async () => {
    const user = Moralis.User.current();
    const options = {
        chain: "eth",
        address: Moralis.User.current().get("ethAddress"), 
      };
      const ownedItems = await Moralis.Web3API.account.getNFTs(options);
  
    ownedItems.result.forEach((item) => {
      getAndRenderItemData(item, renderUserItem);
    });
  };

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].src = item.name;
    userItem.getElementsByTagName("h5")[0].innerText = item.name;
    userItem.getElementsByTagName("p")[0].innerText = item.description;
    userItems.appendChild(userItem);
}

getAndRenderItemData = (item, renderFunction) =>{
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data =>{
        data.symbol = item.symbol;
        data.tokenId = item.tokenId;
        data.tokenAddress = item.tokenAddress;
        renderFunction(data);
    })
}

createItem = async () => {
    if (createItemFile.files.length == 0){
        alert("Please select a file!");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please give the item a name!");
        return;
    }
    mintNft = async (metadataUri) => {
        const receipt = await tokenContract.methods.createItem(metadataUri).send({ from: ethereum.selectedAddress });
        console.log(receipt);
        return receipt.events.Transfer.returnValues.tokenId;
    }

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

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

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

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

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

const nftId = await mintNft(nftFileMetadataFilePath);


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

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

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

const firstTip = document.getElementById("tipConnect1");
const secondTip = document.getElementById("tipConnect2");

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

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

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

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

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

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

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

sorry if it seems i am repeating my questions, i do not understand cloud functions in a decentralized environment.

This means that it will run that request on eth mainnet.

So could i do this?

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

loadUserItems.js

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

if i insert the code above, then these errors show:

You can run this code directly in front end, it will be easier to debug there. You can use console.log also for debugging.