[SOLVED] Stuck at Step 12 on Rarible cloning tutorial - typo in events sync plugin ABI

Hi. I’m stuck at Step 12 of the Rarible cloning tutorial after trying to troubleshoot through multiple means including a previous thread on this forum (Problems with the collumns added in part 12 - rarible clone).

My issue is that the Owner and Token columns are still not showing up in the EthNFTOwners class on my Moralis instance. However I’m not sure where to look next. Other members of the forum have asked me to post my code, which one should I post? My Cloud Functions or main.js?

Any help will be appreciated. Thanks in advance!

What columns you have in EthNFTOwners?

Ah sorry typo, I meant to say the columns that Part 12 talks about are meant to add the Owners and Item columns to the ItemsForSale class.

In my EthNFTOwners class I have:
objectId
token_id
owner_of
token_uri
contract_type
ACL
name
updatedAt
token_address
amount
symbol
createdAt
block_number

On the ItemsForSale class I have:
objectId
askingPrice
block_hash
block_timestamp
ACL
updatedAt
transaction_hash
uid
transaction_index
address
log_index
createdAt
block_number
tokenAddress
tokienId*
confirmed

Thanks for pointing me in this direction. I noticed that one column in the ItemsForSale list is misspelled (marked with an asterisk) where I wrote ‘tokienId’ instead of ‘tokenId’. I traced this typo to abi.js and rectified it there. However when I clear the rows and delete the class then try to mint an NFT again, even after restarting the Moralis server and also my local webserver, the column reappears as ‘tokienId’. I think this is the source of my problem, any tips on how to fix it?

How is ItemsForSale table initialised or how are rows added to it?

Rows are added everytime an NFT is minted and set to instant buy at the point of minting. After deleting the ItemsForSale table, minting an NFT will create this table again.

I mean what is the code that does that row addition, where from it gets the column names?

I believe its from the marketplaceContractAbi which is part of abi.js. The code I have is as follows:

var marketplaceContractAbi = [
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "tokenAddress",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "askingPrice",
          "type": "uint256"
        }
      ],
      "name": "itemAdded",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "buyer",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "askingPrice",
          "type": "uint256"
        }
      ],
      "name": "itemSold",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "itemsForSale",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        },
        {
          "internalType": "address",
          "name": "tokenAddress",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "internalType": "address payable",
          "name": "seller",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "askingPrice",
          "type": "uint256"
        },
        {
          "internalType": "bool",
          "name": "isSold",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "internalType": "address",
          "name": "tokenAddress",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "askingPrice",
          "type": "uint256"
        }
      ],
      "name": "addItemToMarket",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "id",
          "type": "uint256"
        }
      ],
      "name": "buyItem",
      "outputs": [],
      "stateMutability": "payable",
      "type": "function",
      "payable": true
    }
  ];

How does the information from this ABI gets connected to what is in ItemsForSale table?

I believe its from this part of the main.js.

createItem = async () => {
    if (createItemFile.files.length == 0){
        alert("Please select a file.");
        return;
    } else if (createItemNameField.value.length == 0){
        alert("Please enter a name for your item.");
        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 new instance of the class thingy thing thing.
    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;    
        }

}

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

There is a form on the frontend where I enter the information such as the name, price and upload the file associated.

For me it looks like it may be related to this event.
What events you sync with events plugin now?

Ah yes, it was the itemAdded event. I noticed the typo was in the Abi there as well.

The columns appear now, thank you for pointing out where it is. I apologise if I was dense about it, I am rather new to this. Appreciate the help!