soliditysmartcontractsdecentralized-applications

Error: could not decode result data (value="0x", info={ "method": "getCreatorCount", "signature": "getCreatorCount()" }, code=BAD_DATA, version=6.6.2)


I am using solidity and hardhat to create smart contract. Version 6.6.2. Here's how my smart contract looks like:

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

contract CreatorRegistry {
    struct Creator {
        address walletAddress;
        string name;
        string b64Image;
    }

    Creator[] public creators;
    mapping(address => bool) public isCreatorRegistered;

    function signup(address _walletAddress, string memory _name, string memory _b64Image) public {
        require(!isCreatorRegistered[_walletAddress], "Address is already registered");

        Creator memory newCreator;
        newCreator.walletAddress = _walletAddress;
        newCreator.name = _name;
        newCreator.b64Image = _b64Image;

        creators.push(newCreator);
        isCreatorRegistered[_walletAddress] = true;
    }

    function getCreator(uint256 _index) public view returns (
        address walletAddress,
        string memory name,
        string memory b64Image
    ) {
        require(_index < creators.length, "Invalid index");

        Creator storage creator = creators[_index];
        walletAddress = creator.walletAddress;
        name = creator.name;
        b64Image = creator.b64Image;
    }

    function getCreatorCount() public view returns (uint256) {
        return creators.length;
    }
}

And here's how I am trying to invoke the contract:

// javascript frontend
const newUser =
                            (await registrationContract?.getCreatorCount?.()) ??
                            'Oops we lost';
                        console.log('New User = ', newUser);

But it fails with the error:

Error: could not decode result data (value="0x", info={ "method": "getCreatorCount", "signature": "getCreatorCount()" }, code=BAD_DATA, version=6.6.2)

Can someone help me in understanding what's going wrong here?

From the error it seems like its not able to decode the data in javascript side or is it an issue at solidity side? How can I fix this?

Edit 1:

As @Yilmaz mentioned in comments: ?. is an optional chaining operator in javascript which ensures not to crash the program if the attribute remains undefined. However just to be super sure, I did this as well:

const newUserCount =
                            (await registrationContract.getCreatorCount()) ??
                            'Oops we lost';

which failed too.

Edit 2 Github forum: There's a github forum which suggests that due to varied network this issue may show up: https://github.com/web3/web3.js/issues/1629

So I was making sure that I am referring to localhost network and right wallet address. Even after configuring that, I am still getting the same error: enter image description here

This is how my registrationContract looks like:

'use client';
import { Contract, InterfaceAbi, ethers } from 'ethers';
import Web3Modal from 'web3modal';
import { ContractRunner } from 'ethers';
import {
    contentCreatorABI,
    creatorRegistryABI,
    contentCreatorAddress,
    creatorRegistryAddress,
} from './contractClient';
import { Web3Window } from './web3SignIn';

const getSmartContract = (
    address: string,
    abi: InterfaceAbi,
    provider: ContractRunner
): Contract => new ethers.Contract(address, abi, provider);

const getContracts = async (): Promise<{
    error: boolean;
    message?: string;
    data?: { creatorContract?: Contract; registrationContract: Contract };
}> => {
    const { ethereum } = window as Web3Window;
    if (!ethereum)
        return {
            error: true,
            message: 'Please install metamask extension and try refreshing the page',
        };
    try {
        const provider = new ethers.BrowserProvider(ethereum);
        const signer = await provider.getSigner();
        const creatorContract = getSmartContract(
            contentCreatorAddress,
            contentCreatorABI,
            signer
        );
        const registrationContract = getSmartContract(
            creatorRegistryAddress,
            creatorRegistryABI,
            signer
        );

        return { error: false, data: { registrationContract } };
    } catch (err) {
        return { error: true, message: (err as { message: string }).message };
    }
};

export { getContracts };

Solution

  • For me the error was coming because I was getting response from solidity in uint8 which is equivalent to long in javascript and was required to correctly decrypted.

    After decrypting it correctly, the issue went off.

    Here's the final code:

    at client side:

    'use client';
    import { Contract, InterfaceAbi, ethers } from 'ethers';
    import { ContractRunner } from 'ethers';
    import {
        contentCreatorABI,
        creatorRegistryABI,
        contentCreatorAddress,
        creatorRegistryAddress,
    } from './contractClient';
    import { Web3Window } from './web3SignIn';
    
    const getSmartContract = (
        address: string,
        abi: InterfaceAbi,
        provider: ContractRunner
    ): Contract => new ethers.Contract(address, abi, provider);
    
    const getContracts = async (): Promise<{
        error: boolean;
        message?: string;
        data?: { creatorContract: Contract; registrationContract: Contract };
    }> => {
        const { ethereum } = window as Web3Window;
        if (!ethereum)
            return {
                error: true,
                message: 'Please install metamask extension and try refreshing the page',
            };
        try {
            const provider = new ethers.BrowserProvider(ethereum);
            const signer = await provider.getSigner();
            const creatorContract = getSmartContract(
                contentCreatorAddress,
                contentCreatorABI,
                signer
            );
            const registrationContract = getSmartContract(
                creatorRegistryAddress,
                creatorRegistryABI,
                signer
            );
    
            return { error: false, data: { registrationContract, creatorContract } };
        } catch (err) {
            return { error: true, message: (err as { message: string }).message };
        }
    };
    
    export { getContracts };
    

    And here's how I invoke it:

    'use client';
    import { loginWithWallet } from '@@/solidity/web3SignIn';
    import useWeb3Store from '@@/store/web3Walltet';
    import classes from './MetaMaskLogin.module.css';
    import { useEffect, useState } from 'react';
    import { getContracts } from '@@/solidity/contracts';
    import { useRouter } from 'next/navigation';
    import { NormalImage } from '@@/components/NormalImage';
    
    const MetaMaskLogin = () => {
        const {
            setAccount,
            setNameAndImg,
            setCreatorContract,
            setRegistrationContract,
            registrationContract,
            account,
        } = useWeb3Store();
        const [loading, setLoading] = useState(false);
        const [error, setError] = useState<string | null>(null);
        const [firstTime, setFirstTime] = useState(false);
        const [uName, setUName] = useState('');
        const [imgUrl, setImgUrl] = useState(
            'https://www.gravatar.com/avatar/00000000000000000000000000000000'
        );
    
        const router = useRouter();
    
        const loginToMetaMask = async () => {
            setLoading(true);
            loginWithWallet()
                .then((account) => {
                    if (account) {
                        setAccount(account);
                    } else
                        setError(
                            'Unexpected error occured while logging in. Please refresh the page and retry.'
                        );
                })
                .catch((error) => {
                    setError(`Error occured while logging in: ${error.message}`);
                })
                .finally(() => setLoading(false));
        };
    
        const getUserDetails = async () => {
            if (registrationContract)
                try {
                    const newUserCount =
                        (await registrationContract.getCreatorByAddress(account)) ??
                        'Oops we lost';
                    const [_, name, b64Image] = newUserCount;
                    if (name === 'Not Found') setFirstTime(true);
                    else {
                        setFirstTime(false);
                        setNameAndImg(name, b64Image);
                        //TODO: Redirect to main page
                        router.push('/');
                    }
                } catch (err) {
                    console.log('Error occured with smart contract = ', err);
                }
        };
    
        useEffect(() => {
            if (account) {
                setLoading(true);
                getContracts()
                    .then(async ({ error, data, message }) => {
                        if (!error && data) {
                            const { creatorContract, registrationContract } = data;
                            setCreatorContract(creatorContract);
                            setRegistrationContract(registrationContract);
                        } else
                            setError(
                                `Error occured while fetching smart contracts: ${
                                    message ?? 'Unknown error'
                                }`
                            );
                    })
                    .catch((error) => setError(error.message))
                    .finally(() => setLoading(false));
            }
        }, [account, setCreatorContract, setRegistrationContract]);
    
        useEffect(() => {
            getUserDetails();
            // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [registrationContract]);
    
        const registerUser = async () => {
            setLoading(true);
            if (registrationContract) {
                const user = await registrationContract.signup(account, uName, imgUrl);
                await user.wait();
                setFirstTime(false);
                //TODO: Redirect to main page
                setLoading(false);
                router.push('/');
            }
        };
    
        return (
            <div className={classes.container}>
                <NormalImage
                    className={classes.metamaskLogo}
                    src='/meta-mask.png'
                />
                {loading ? (
                    <p className={classes.SignInText}>Loading...</p>
                ) : (
                    <button
                        className={'StandardButton'}
                        onClick={loginToMetaMask}
                    >
                        Login to Metamask
                    </button>
                )}
                {error != null && <p className={classes.ErrorText}>{error}</p>}
                {firstTime && (
                    <>
                        <input
                            type='text'
                            className={classes.Input}
                            placeholder='Please Input your Name'
                            value={uName}
                            onChange={(e) => setUName(e.target.value)}
                        />
                        <input
                            type='url'
                            className={classes.Input}
                            placeholder='Please Input your Image Avatar URL'
                            value={imgUrl}
                            onChange={(e) => setImgUrl(e.target.value)}
                        />
                        <button
                            className='StandardButton'
                            onClick={registerUser}
                        >
                            Complete Registration
                        </button>
                    </>
                )}
            </div>
        );
    };
    
    export default MetaMaskLogin;
    

    At server side:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.18;
    
    contract CreatorRegistry {
        struct Creator {
            address walletAddress;
            string name;
            string b64Image;
        }
    
        Creator[] public creators;
        mapping(address => bool) public isCreatorRegistered;
    
        function signup(address _walletAddress, string memory _name, string memory _b64Image) public {
            require(!isCreatorRegistered[_walletAddress], "Address is already registered");
    
            Creator memory newCreator;
            newCreator.walletAddress = _walletAddress;
            newCreator.name = _name;
            newCreator.b64Image = _b64Image;
    
            creators.push(newCreator);
            isCreatorRegistered[_walletAddress] = true;
        }
    
        function getCreator(uint256 _index) public view returns (
            address walletAddress,
            string memory name,
            string memory b64Image
        ) {
            require(_index < creators.length, "Invalid index");
    
            Creator storage creator = creators[_index];
            walletAddress = creator.walletAddress;
            name = creator.name;
            b64Image = creator.b64Image;
        }
    
        function getCreatorCount() public view returns (uint256) {
            return creators.length;
        }
    
        function getCreatorByAddress(address _walletAddress) public view returns (
            address walletAddress,
            string memory name,
            string memory b64Image
        ) {
            for (uint256 i = 0; i < creators.length; i++) {
                Creator storage creator = creators[i];
                if (creator.walletAddress == _walletAddress) {
                    walletAddress = creator.walletAddress;
                    name = creator.name;
                    b64Image = creator.b64Image;
                    return (walletAddress, name, b64Image);
                }
            }
    
            // Creator not found
            return(walletAddress, "Not Found", "Not Found");
        }
    }