Rarible clone episode 7: The "attributes" is not showing the token ID, I am also deploying 2 objects somehow

Hello,
for the tutorial in part 7: I believe I deployed everything perfectly, but when I click on “Mint NFT” after paying the metamask, the log shows that I create 2 objects + the “attributes” section is empty.

Which part of the code do I need to fix/ which function makes the “attributes” in the logs?

main.js:
“”"
Moralis.initialize(“3IcvId63X3g2jWHA2t2OCOFDHmfOw3PbF9etB6Mt”);
Moralis.serverURL = ‘https://k8lq9f7lkimp.moralis.io:2053/server’
const TOKEN_CONTRACT_ADDRESS = “0x9fA230c6465ad8ceDa74A97946bDc4Ab2DD29F6e”

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

initUser();

}

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

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){
        userAvatarImage.src = userAvatar.url();
        showElement(userAvatarImage);
    }else{
        hideElement(userAvatarImage);
    }
    showElement(userInfo);
}else{
    login();
}

}

saveUserInfo = async() => {
user.set(‘email’, userEmailField.value);
user.set(‘username’, userUsernameField.value)
if (userAvatarFile.files.length > 0) {
const file = userAvatarFile.files[0];
const name = “avatar.jpg”;

    const avatar = new Moralis.File(name, file);
    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);



// Simple syntax to create a new subclass of Moralis.Object.
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('nftFileMetadataFilePath', nftFileMetadataFilePath);
item.set('nftFileMetadataFileHash', 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 = (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 userAvatarImage = 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;

init(); “”"

index.html:
“”"

Latin Ark
Connect Wallet Profile Create
<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="" alt="" id="imgAvatar">
    <label for="fileAvatar">Select your 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 Item 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 NFT!</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>
"""

Morarable.sol:
“”"
pragma solidity ^0.8.0;

import “…/node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol”;
import “…/node_modules/@openzeppelin/contracts/utils/Counters.sol”;

contract Arktoken is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;

constructor () ERC721("Arktoken","ARK"){}

struct Item {
    uint256 id;
    address creator;
    string uri;
}

mapping(uint256 => Item) public Items;

function createItem(string memory uri) public returns (uint256){
    _tokenIds.increment();
    uint256 newItemId = _tokenIds.current();
    _safeMint(msg.sender, newItemId);

    Items[newItemId] = Item(newItemId, msg.sender, uri);

    return newItemId;
}

function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), “ERC721Metadata: URI query for nonexistent token”);

    return Items[tokenId].uri;
}

}
“”"

2 Likes

Please double-check our common issues at FAQ - Common Issues & How To Get Help as well as how to properly submit if you didn’t manage to find a solution on your own. This will speed up the process, so we can help you as soon as possible.

1 Like