NFT Game series Error

Iā€™ve been having a few issues going through the Youtube videos, and my renderGame() function hasnā€™t been processing.
I saw it might be the version of Web3 and to type contract instead of Contract but it gave another error when trying to getAllTokensForUser

The NFTs are visible in the Terminal but might not be posting, I saw the first NFT created but itā€™s gone. I read in another Thread it might be because Iā€™m using a local Ganache server.

Currently Iā€™m receiving an error about the Contract and Web3 warnings:
Uncaught (in promise) TypeError: Cannot read property ā€˜Contractā€™ of undefined

image

This is my code:

 async function renderGame(){
    $("#login_button").hide();
    $("#zilla_row").html("");
    //Get and Render properties from Smart Contract
    window.Web3 = await Moralis.Web3.enable();
    let abi = await getAbi();
    let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
    let array =  await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress});
    if(array.length == 0) return;
    array.forEach( async (ZillaId) => {
        let details = await contract.methods.getTokenDetails(ZillaId).call({from: ethereum.selectedAddress});
        renderzilla(ZillaId, details);
    });
    $("#game").show();

And this is my Server URL

https://93japsubcmcm.moralisweb3.com:2053/server

Hey @LonelyZeta

Try to use window.ethereum instead of window.Web3 .

But the bes solution is creating a new const web3:

const web3 = await Moralis.Web3.enable();
1 Like

Thanks for the assistance, but I ran into a different error when switching it.

image

For these lines of code

login 13

renderGame();

RenderGame 24

const web3 = await Moralis.Web3.enable();

RenderGame 26

 let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);

Any clue why?


async function login() {
    try {
        let user = Moralis.User.current();
        if(!user){
            $("#login_button").click( async () => {
                user = await Moralis.Web3.authenticate();
            })
        renderGame();
        }
    } catch (error) {
        console.log(error);
    }
}

 async function renderGame(){
    $("#login_button").hide();
    $("#zilla_row").html("");
    //Get and Render properties from Smart Contract
    const web3 = await Moralis.Web3.enable();
    let abi = await getAbi();
    let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
    let array =  await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress});
    if(array.length == 0) return;
    array.forEach( async (ZillaId) => {
        let details = await contract.methods.getTokenDetails(ZillaId).call({from: ethereum.selectedAddress});
        renderZilla(ZillaId, details);
    });
    $("#game").show();
    
}

function renderzilla(id, data){
    let htmlString = `
    <div class="col-md-4 card" id="zilla_${id}">
        <img class= "card-img-top zilla_img" src="ruby.png">
        <div class="card-body">
            <div>Id: <span class="#zilla_${id}"></span></div>
            <button data-zilla-id="${id}" class="travel_button btn btn-primary btn-block">Travel to a new Location!</button>
        </div>

    </div>`;

    let element = $.parseHTML(htmlString);
    $("#zilla_row").append(element);

    $(`zilla_${id} .travel_button`).click( () => {
        travel(id);
    });

}   
    

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


async function travel(ZillaId){
    let abi = await getAbi();
    let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
    contract.methods.travel(ZillaId).send({from: ethereum.selectedAddress}).now("receipt", ( () => {
        console.log("done");
        renderGame();
    }))

}

document.getElementById("login_button").onclick = login;```

Hey @LonelyZeta

You have an error message, so check all addresses you provide to web3 functions. Make console.log() before calling the functions with addresses
image

1 Like

Thanks. Found another error after this with that tip.

Iā€™m getting a different error with the contract.
ā€œTypeError: contract.methods.getAllTokensForUser is not a function
at renderGame (main.js:29)ā€

 async function renderGame(){
        $("#login_button").hide();
        $("#zilla_row").html("");
        //Get and Render properties from Smart Contract
        const web3 = await Moralis.Web3.enable();
        let contract = new web3.eth.Contract(contractABI, CONTRACT_ADDRESS);
        let array =  await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress});
        if(array.length == 0) return;
            array.forEach( async (ZillaId) => {
                let details = await contract.methods.getTokenDetails(ZillaId).call({from: ethereum.selectedAddress});
                renderZilla(ZillaId, details);
        });
        $("#game").show();
}```



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

Token.sol includes this function above, but would contract.methods. be the correct way to pull/request it to deploy?

Or am I confused on how to define the ā€œpetIdā€ and define functions?

Hey @LonelyZeta

You can call read methods without specifing who is calling the function.

Use .call() instead of .call({from: ethereum.selectedAddress})

Let me know how it will work for you :man_mechanic:

1 Like

I added a consol.log(user); to view the success instead of using a catch error when logging in/logged in.

removed the call specification and it is still a showing:

Uncaught (in promise) TypeError: contract.methods.getAllTokensForUser is not a function at renderGame

async function init() {
        let user = Moralis.User.current();
        console.log(user);
            $("#login_button").click( async () => {
                user = await Moralis.Web3.authenticate();
            })
        renderGame();  
}

 async function renderGame(){
        $("#zilla_row").html("");
        let abi = await getAbi();
        const web3 = await Moralis.Web3.enable();
        let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
        let array =  await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call();
        if(array.length == 0) return;
            array.forEach( async (ZillaId) => {
                let data = await contract.methods.getTokenDetails(ZillaId).call();
                renderZilla(ZillaId, data);
        });
        $("#login_button").hide();
        $("#game").show();
}

Just to be sure, please check the correctness of the ABI, the smart contract address and chain id.

I reccomend you to add:

let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
console.log(contract)

And take a look at what does it have

1 Like

Thank you so much! Iā€™ve been hitting a wall for too many work hours.

I wasnā€™t able to understand the output (besides the contract address being correct) so I ran another migrate reset, deleted my old token.json to reload, and now the function works and logs the pet details, and renderpet renders the html perfectly for now.

Iā€™ll continue on the series and try to complete it. Hope there isnā€™t other problems to stumble on.

1 Like

Awesome @LonelyZeta!

Just #BUIDL it :man_mechanic:

1 Like

Hi, I have used the code learned from the tutorial and I have also checked my code with those posted by LonlyZeta, which is almost the same as well, but I have encounter an error.

I was wondering whether this error arose from the abi, but I have followed the tutorial several times and I couldnā€™t see where I did wrong.

Any advice?

error moralis

Hey @jojowamikko

Itā€™s a bit tricky to answer. There can be many reasons why this is happening. For example, an incorrectly specified address, an incorrect abi. Perhaps you are inputting address not as a string but as a HEX number.

Please provide more information and code exmaple :man_mechanic:

Here we go. I have followed the tutorial several times to make my code of main.js, and the contract address should be correct. I poste the code here:

const CONTRACT_ADDRESS = "0x6A5B2E60eAC36CcFB7B9f7353822E09f96c81104"

async function init() {
    try {
        let user = Moralis.User.current();
        if(!user){
            $("#login_button").click( async () => {
                user = await Moralis.Web3.authenticate();
            })
            console.log(user)
        }
        renderGame();

    } catch (error) {
        console.log(error);
    }
}

async function renderGame(){
    $("#login_button").hide();
    $("#pet_row").html("");
    // get and render properties from smart contract
    const web3 = await Moralis.Web3.enable();
    let abi = await getAbi();
    let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);
    let array = await contract.methods.getAllTokensForUser(ethereum.selectedAddress).call({from: ethereum.selectedAddress});  
    if(array.length == 0) return;
    array.forEach(async (petId) => {
        let details = await contract.methods.getTokenDetails(petId).call({from: ethereum.selectedAddress});
        renderPet(petId, details);
    });
    $("#game").show();
}

function renderPet(id, data){
    let now = new Date();
    let maxTime = data.endurance;
    let currentUnix = Math.floor(now.getTime() / 1000);
    let secondsLeft = (parseInt(data.lastMeal) + parseInt(data.endurance)) - currentUnix;
    let percentageLeft = secondsLeft / maxTime;
    let percentageString = percentageLeft * 100 + '%';
    let deathTime = new Date( (parseInt(data.lastMeal) + parseInt(data.endurance))  * 1000);
    let interval = setInterval( () => {
        let now = new Date();
        let maxTime = data.endurance;
        let currentUnix = Math.floor(now.getTime() / 1000);
        let secondsLeft = (parseInt(data.lastMeal) + parseInt(data.endurance)) - currentUnix;
        let percentageLeft = secondsLeft / maxTime;
        let percentageString = percentageLeft * 100 + '%';
        $(`#pet_${id}.progress-bar`).CONTRACT_ADDRESS("width", percentageString);
        if(percentageLeft<0){
            clearInterval(interval);
        }
    },5000)
    let htmlString = `
    <div class="col-md-3 card mx-1" id="pet_${id}">
        <img class="card-img-top pet_img" src="pet.png">
        <div class="card-body">
            <div>Id: <span class="pet_id">${id}</span></div>
            <div>Damage: <span class="pet_damage">${data.damage}</span></div>
            <div>Magic: <span class="pet_magic">${data.magic}</span></div>
            <div>Endurance: <span class="pet_endurance">${data.endurance}</span></div>
            <div>Time to starvation: <span class="pet_starvation_time">${deathTime}</span></div>
            <div class="progress">
                <div class="progress-bar" style="width: ${percentageString};">
                </div>
            </div>
            <button data-pet-id="${id}" class="feed_button btn btn-primary btn-block">Feed</button>
        </div>    
    </div>`;
    let element = $.parseHTML(htmlString);
    $("#pet_row").append(element);
    $(`#pet_${id}.feed_button`).click( () => {
        feed(id);
    });
}

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

async function feed(petId){
    let abi = await getAbi();
    
    const web3 = await Moralis.Web3.enable();
    let contract = new web3.eth.Contract(abi, CONTRACT_ADDRESS);

    console.log(contract.methods.feed(petId))

    contract.methods.feed(petId).send({from: ethereum.selectedAddress}).now("receipt", ( () => {
        console.log("done");
        renderGame();
    }))
}

init();

And I have an error as previous one:
error moralis 2

Hi @jojowamikko,

Please let me know what ABI you used. Probably the ABI is incorrect. Share it with us to double check it ourselves.

Hope this helps. :slight_smile:

Hi @malik

I have used the getAbi function to get it from Token.json

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

for Token.json, I have followed the tutorial, coped from the build folder. I am sharing the document here.

Token.json

Hi gentlemen @malik @Yomoo

Did I code something wrong? Hope to have any advice from you.

Thanks in advance.

Hi,

I would suggest you to console log the abi response and see if youā€™re receiving it in the correct format.

Sry I didnā€™t get your point at first. Here I made a console log as follows

let abi = await getAbi();
console.log(abi);

And what I got is this

Is there anything wrong?

Hi @jojowamikko,

The ABI seems to be fine.

Now there can be other common issues -

  1. Did you confirm the contract address is the same as the one you deployed (If youā€™re using ganache)
  2. Are you able to do other transactions on the local ganache blockchain other than contract interaction?
  3. There might be some config issue in your wallet. Make sure you connected it to your local blockchain instance correctly.

Itā€™s most likely a config issue and not a code issue. Make sure your setup was right. Let me know how it goes.