Problems with the collumns added in part 12 - rarible clone

Hello there! Im having problems with this part of the tutorial. I’ve already watched the part 7.5 and as far as I know I made the changes that was indicated in that video.
This is the cloud functions code

Moralis.Cloud.define("getUserItems", async (request) => {
  
  const query = new Moralis.Query("EthNFTTokenOwners");
  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({
     "id": queryResults[i].attributes.objectId,
     "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("EthNFTTokenOwners");
  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({userMasterKey: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({userMasterKey:true});
    if (userObject) {
     request.object.set('user', userObject); 
    }
    
  } 
});

Everything is working just fine, can you guys help me with that? Thaaanks a lot

What doesnt work specifically?

The two columns that should be added in the “Items for Sale” table are not added

@fralz Hi!

The columns will be added on all new rows that are inserted into the table.
Try adding a new Item to the market place and check again.
If they still does not appear, let us know :slight_smile:

I’ve added new Items but still does no appear. Dont know if this info helps, but the three 3 notifications in metamask are appearing.
Im revisiting the main.js and the marketplace code to see if I made a typo mistake. Can I post thecode here?
Thank you for the help :slight_smile:

marketplace js

pragma solidity ^0.8.0;

import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";

contract MorarableMarketContract{
    struct AuctionItem {
        uint256 id;
        address tokenAddress;
        uint256 tokenId;
        address payable seller;
        uint256 askingPrice;
        bool isSold;
    }

    AuctionItem[] public itemsForSale;
    mapping(address => mapping(uint256 => bool)) activeItems;

    event itemAdded(uint256 id, uint256 tokenId, address tokenAddress, uint256 askingPrice);
    event itemSold(uint256 id, address buyer, uint256 askingPrice);

    modifier OnlyItemOwner(address tokenAddress, uint256 tokenId){
        IERC721 tokenContract = IERC721(tokenAddress);
        require(tokenContract.ownerOf(tokenId) == msg.sender);
        _;   
    }

     modifier HasTransferApproval(address tokenAddress, uint256 tokenId){
        IERC721 tokenContract = IERC721(tokenAddress);
        require(tokenContract.getApproved(tokenId) == address(this));
        _;
    }

    modifier ItemExists(uint256 id){
        require(id < itemsForSale.length && itemsForSale[id].id == id, "Could not find item");
        _;
    }

    modifier IsForSale(uint256 id){
        require(itemsForSale[id].isSold == false, "Item is already sold!");
        _;
    }

    function addItemToMarket(uint256 tokenId, address tokenAddress, uint256 askingPrice) OnlyItemOwner(tokenAddress,tokenId) HasTransferApproval(tokenAddress,tokenId) external returns (uint256){
        require(activeItems[tokenAddress][tokenId] == false, "Item is already up for sale!");
        uint256 newItemId = itemsForSale.length;
        itemsForSale.push(AuctionItem(newItemId, tokenAddress, tokenId, payable(msg.sender), askingPrice, false));
        activeItems[tokenAddress][tokenId] = true;

        assert (itemsForSale[newItemId].id == newItemId);
        emit itemAdded(newItemId, tokenId, tokenAddress, askingPrice);
        return newItemId;
    }

    function buyItem(uint256 id) payable external ItemExists(id) IsForSale(id) HasTransferApproval(itemsForSale[id].tokenAddress,itemsForSale[id].tokenId){
        require(msg.value >= itemsForSale[id].askingPrice, "Not enough funds sent");
        require(msg.sender != itemsForSale[id].seller);

        itemsForSale[id].isSold = true;
        activeItems[itemsForSale[id].tokenAddress][itemsForSale[id].tokenId] = false;
        IERC721(itemsForSale[id].tokenAddress).safeTransferFrom(itemsForSale[id].seller, msg.sender, itemsForSale[id].tokenId);
        itemsForSale[id].seller.transfer(msg.value);

        emit itemSold(id, msg.sender, itemsForSale[id].askingPrice);
    }
}

main js

Moralis.initialize("Brk5nQTXZrDTd5d0MaYQt7qMRDacfou4s9VN8bYc");
Moralis.serverURL = 'https://skjw7fdcguay.moralis.io:2053/server';
const TOKEN_CONTRACT_ADDRESS = "0x87Fe182737A6301f8D0579Ca87eB7e050F4f2C09";
const MARKETPLACE_CONTRACT_ADDRESS = "0x7988C436396575030551B4c3A3C839e483Be6841";

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

initUser = async () => {
    if (await Moralis.User.current()){ //se estou logado
        hideElement(userConnectButton);
        showElement(userProfileButton);
        showElement(openCreateItemButton);
        showElement(openUserItemsButton);
        loadUserItems();
    }else{       // se estou deslogado
        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();
    }  
}

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

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

    // Create a new instance of that class.
    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(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;
}

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(response => response.json())
    .then(data => {
        data.symbol = item.symbol;
        data.tokenId = item.tokenId;
        data.tokenAddress = item.tokenAddress;
        renderFunction(data);
    })
}

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

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

init();

Thank you, Can I get a screenshot of your plugins as well? Want to see what values you used when subscribing to the events. Also, are you running the latest version of the server?

Sure, here it is




Yes, im running the latest version of the server, version 0.0.185

You seem to be using “userMasterKey” instead of “useMasterKey” in both cloud functions. That would explain it

Ok, I corrected that but the problem continues. I already reset de server and everything

The ItemsForSale are being created but the columns are not being added :frowning:

In your cloud functions, try changeing the triggered table from: “itemsForSale” to “ItemsForSale”

Hi @Capplequoppe,

i hope you are fine. I’m having the same issue here. I came to part 12 of the Rarible clone and those two columns aren’t appearing in the ItemsForSale.

I went back to episode 7.5 and did everything what is described there. Also deleted the class ItemsForSale. Now the situation got worse. Table ItemsForSale doesn’t appear anymore. Server is now at 0.0.221 version.
I created new new NFTs, got 3 Metamask windows and confirm them all, but the ItemsForSale table isn’t appearing anymore.

I will appreciate your help :pray:

Cloud functions are here:

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

  const query = new Moralis.Query("EthNFTTokenOwners");
  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({
      "id": queryResults[i].attributes.objectId,
      "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("EthNFTTokenOwners");
  query.equalTo("token_address", request.object.get('tokenAddress'));
  query.equalTo("tokenId", 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')); //id is already used by Moralis, so it replace it with 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);  
    }
    
  }
});

Hey @vasja !
As of yesterday we have some breaking changes, see this article: https://moralis.io/introducing-the-moralis-big-evm-update-version-0-0-221/

Let me know if your problem persists.

Hi,

thanks! I checked it. I made a new server in that time and now also the table EthNFTOwner isn’t appearing anymore. I don’t know how to proceed :confused:

Ok.

Can you provide the latest cloud code as well as the subdomain for your server?

Hi,

thanks for you willingness to help.
Subdomain: https://vs0vp64xzidd.moralis.io:2053/server

-I now see ItemsForSale but I don’t see the last two columns that we add in part 12.
-I don’t see the EthNFTOwners and EthNFTTransfers
-And const ownedItems = await Moralis.Cloud.run(“getUserItems”); doesn’t work anymore

Cloud functions ( I changed EthNFTTokenOwners to EthNFTOwners ) as said in the changes 0.221

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({
      "id": queryResults[i].attributes.objectId,
      "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("tokenId", 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')); //id is already used by Moralis, so it replace it with 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);  
    }
    
  }
});

Cloud functions that works:

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}); //you need masterkey to access user table
    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')); //id is already used by Moralis, so it replaces it with 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);  
    }
    
  }
});

Hi, I’m following along with the same Rarible cloning tutorial and I’ve run into the same problem, even trying @vasja’s above cloud functions I can’t get the owner and token columns to appear on my ItemsForSale table. I’m not sure where to continue my troubleshooting.

Please create a new thread and share your code and errors :raised_hands: