RaribleClone ep 9 - no nftTokenOwners table

I don’t have an “nftTokenOwners” table in my dashboard, and no table to query that contains both the owner wallet address and metadata. Is this table just not included in the latest update, or is there an issue in my code?

I should also state that I am currently using the 0.0.218 update. Thanks!

Hi,

The table names have changed. it is now - “EthNFTTokenOwners”

Hope this helps

I have EthNFTTokenTransfers, EthTransfers, Item and _EthAddress, but no EthNFTTokenHolders in the dashboard.

Could you post your code here so that we can evaluate your issue. Thank you.

I also have the feeling that suddenly EthNFTTokenHolders doesn’t show any new minted tokens anymore although we didn’t change anything in the deployed code since executing it successfully. at the end of last week. Not sure if that problem we had before or if the problem is inside of our code for mystic reasons.

I am also now having a sort of mystical problem. Haven’t changed anything thatI can recall but I’m now having a hard time getting saved user avatar to render after connecting wallet, or saving any new user data. Haven’t tried minting new NFT yet since these problems began. I’ll post my code here in a moment.

Moralis.initialize("9quLXz9G6OoV6LXrakGsZQNPvCiTu9Fo5NJ0DN7y");
Moralis.serverURL = "https://sqmfav2bsl7q.moralis.io:2053/server";

const TOKEN_CONTRACT_ADDRESS = "0x9b22914bfF952c89a8F822fE38beF74CCF287616";

//Nav bar
const userInfo = document.getElementById("userInfo");
const userConnectButton = document.getElementById("btnConnect");
const userProfileButton = document.getElementById("btnUserInfo");

//User Profile
const userUsernameField = document.getElementById("txtUsername");
const userEmailField = document.getElementById("txtEmail");
const userAvatarFile = document.getElementById("fileAvatar");
const userAvatarImg = document.getElementById("imgAvatar");
const openCreateItemButton = document.getElementById("btnOpenCreateItem");
const closeCreateItemButton = document.getElementById("btnCloseCreateItem");
const createItemForm = document.getElementById("createItem");

//Upload item
const createItemNameField = document.getElementById("txtCreateItemName");
const createItemDescriptionField = document.getElementById(
  "txtCreateItemDescription"
);
const createItemPrice = document.getElementById("numCreateItemPrice");
const createItemStatus = document.getElementById("selectCreateItemStatus");
const createItemFile = document.getElementById("fileCreateItemFile");

init = async () => {
  hideElement(userItemsSection);
  hideElement(userInfo);
  hideElement(createItemForm);
  window.web3 = await Moralis.Web3.enable();
  window.tokenContract = new web3.eth.Contract(
    tokenContractAbi,
    TOKEN_CONTRACT_ADDRESS
  );

  initUser();
};

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

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

hideElement = (e) => {
  e.style.display = "none";
};

showElement = (e) => {
  e.style.display = "block";
};

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

login = async () => {
  try {
    await Moralis.Web3.authenticate();
    initUser();
  } catch (error) {
    alert(error);
  }
};

userConnectButton.onclick = login;

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

userProfileButton.onclick = openUserInfo;
logout = async () => {
  await Moralis.User.logOut();
  hideElement(userInfo);
  initUser();
};
document.getElementById("btnCloseUserInfo").onclick = () =>
  hideElement(userInfo);

document.getElementById("btnLogout").onclick = logout;

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

  if (userAvatarFile.files.length > 0) {
    const avatar = new Moralis.File("avatar.jpg", userAvatarFile.files[0]);
    user.set("avatar", avatar);
  }

  await user.save();
  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");
  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].alt = 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((res) => res.json())
    .then((data) => {
      data.symbol = item.symbol;
      data.tokenId = item.tokenId;
      data.tokenAddress = item.tokenAddress;
      renderFunction(data);
    });
};

document.getElementById("btnCreateItem").onclick = createItem;

document.getElementById("btnSaveUserInfo").onclick = saveUserInfo;

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

closeCreateItemButton.onclick = () => hideElement(createItemForm);

//user items

const userItemsSection = document.getElementById("userItems");
const userItems = document.getElementById("userItemsList");

const openUserItemsBtn = document.getElementById("btnMyItems");
const closeUserItemsBtn = document.getElementById("btnCloseUserItems");
openUserItemsBtn.onclick = openUserItems;

closeUserItemsBtn.onclick = () => hideElement(userItemsSection);

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

Fixed this second problem for now, but I am still stuck at trying to find an “EthNFTTokenHolders” table in the dashboard.

Problem solved! For anyone following the rarible clone tutorial, keep going past this point, when you complete the market contract section the EthNFTTokenOwners will appear in the dashboard.

3 Likes

Thank you for updating with the solution and the suggestion. Cheers.

thank you for clearing the way.