[SOLVED] NFT Game (part 5) getAllTokensForUser returning an empty array

I’m following the 5th part of the NFT game series, and something there doesn’t seem to work,
let array = await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress}); returns an empty array: image

main.js

const serverUrl = "https://8pxcb5fhmhkk.usemoralis.com:2053/server";
const appId = "cyg7GhprJkJr1PlmgR0sy7HyThqleQ0xiFsXFIaB";
const CONTRACT_ADDRESS = "0xa76ce574515808A382B63BE9f9b27AE9892830C9";
Moralis.start({ serverUrl, appId });

async function login() {
    let user = Moralis.User.current();
    if (!user) {
        try {
            user = await Moralis.authenticate({ signingMessage: "Hello World!" })
            console.log(user)
            console.log(user.get('ethAddress'))
        } catch (error) {
            console.log(error)
        }
        renderGame();
    } else if (ethereum.isConnected()) {
        renderGame();
    }
}

async function logOut() {
    await Moralis.User.logOut();
    console.log("logged out");
    logoutGame();
}

async function renderGame() {
    $("#btn-logout").show();
    $("#btn-login").hide();
    $("#pet-row").html("");

    const web3 = await Moralis.enableWeb3();
    let abi = await getAbi();
    console.log(abi);
    const contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
    console.log(contract);
    let array = await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress});
    console.log(array);
    if (array.length == 0) {
        return;
    }
    array.forEach(async plotId => {
        let data = await contract.methods.getTokenDetails(plotId).call({from: ethereum.selectedAddress});
        renderPlot(0, data);
    });

    $("#game").show();
}

function renderPlot(id, data) {
    let htmlString = `
    <div class="plot-tab" id="plot-${id}">            
        <img class="plot_img" src="assets/156-1561328_back-326-kb-floating-island-voxel.png">
        <div class="stats">
            <div>ID: <span class="plot_id">${id}</span></div>
            <h3 class="h3-stats-title">Position</h3>
            <div>X: <span class="plot_xPos">${data.xPos}</span></div>
            <div>Y: <span class="plot_yPos">${data.yPos}</span></div>
        </div>
    </div>`;

    let element = $.parseHTML(htmlString);
    $("#plot-row").append(element);
}

function getAbi() {
    return new Promise((res) => {
        $.getJSON("Token.json", ((json) => {
            res(json.abi);
        }))
    })
}

async function logoutGame() {
    $("#game").hide();
    $("#btn-logout").hide();
    $("#btn-login").show();
}

document.getElementById("btn-login").onclick = login;
document.getElementById("btn-logout").onclick = logOut;

index.html

<!DOCTYPE html>
<html lang=en>

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial" />
    <title>ETH CITY</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <link rel="stylesheet" href="style.css">
    <link rel="shortcut icon" href="assets/141.jpg">
</head>

<body>
    <main>
        <section class="glass">
            <div class="container">
                <input type="image" id="btn-login" src="assets/MetaMask_Fox.svg.png" alt="Login With MetaMask"
                    name="Login With MetaMask">
                <button id="btn-logout">Logout</button>
                <div id="game">
                    <div class="row" id="plot-row">
                        
                    </div>
                </div>
            </div>
            </div>
        </section>
    </main>
    <script type="text/javascript" src="./main.js"></script>
</body>

</html>

Token.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

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

contract Token is ERC721, Ownable {
    struct Plot {
        uint256 yPos; // Y Position on the map
        uint256 xPos; // X Position on the map
    }

    uint256 nextId = 0;

    mapping(uint256 => Plot) private _tokenDetails;

    constructor(string memory name, string memory symbol)
        ERC721(name, symbol)
    {}

    function getTokenDetails(uint256 tokenId)
        public
        view
        returns (Plot memory)
    {
        return _tokenDetails[tokenId];
    }

    function mint(uint8 yPos, uint8 xPos) public onlyOwner {
        _tokenDetails[nextId] = Plot(yPos, xPos);
        _safeMint(msg.sender, nextId);
        nextId++;
    }

    function getAllTokensForUser(address user)
        public
        view
        returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(user);
        if (tokenCount == 0) {
            return new uint256[](2);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 totalPlots = nextId;
            uint256 resultIndex = 0;
            uint256 i;
            for (i = 0; i < totalPlots; i++) {
                //check
                if (ownerOf(i) == user) {
                    result[resultIndex] = i;
                    resultIndex++;
                }
            }
            return result;
        }
    }
}

2_token_migration.js

const Token = artifacts.require("Token");

module.exports = async function (deployer) {
  await deployer.deploy(Token, "ETHCITY", "ETHC");
  let tokenInstance = await Token.deployed();
  await tokenInstance.mint(0, 0); //Token ID 0
  await tokenInstance.mint(1, 0); //Token ID 1
  let plot0 = await tokenInstance.getTokenDetails(0);
  let plot1 = await tokenInstance.getTokenDetails(1);
  console.log(plot0);
  console.log(plot1);
};

if you call that function then it works fine?

It only works if I put it outside of the: array.forEach(async plotId => { but the array list will still be empty, and when its in the forEach loop it doesnt even get there since it fails on making the array list.

I’m trying to understand if you connect to the right chain to get that info

I honestly don’t know, I am kind of new to Moralis and NFT game developing.

can you try to call that getTokenDetails function? it seems to be a more predictable function
if it works then you know that you are doing the right thing and maybe is a problem with the parameters or with the contract code in the other case

I called the getTokenDetails function instead and now it does load the correct number of rows, but they are exact duplicates of each other, instead of having different ID’s and X and Y positions.

Okay, I fixed it now by modifying a few lines in the original function and now it works.
Thanks for guiding me!