Guilherme Felipe Reis
Guilherme Felipe Reis

Reputation: 918

Web3: Cannot read properties of null after new ethers.Contract

I am trying to use a smart contract just after I instantiate it. However, I get an error:

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'call')

I thought I did not have access to the functions just after instantiating it, but it does not seem to be it. What else could it be? Someone already had a similar problem?

Current code:

import React, { useEffect, useState } from 'react';
import Head from 'next/head';

import { useWeb3React } from '@web3-react/core';
import NFTCollectionArtifact from 'artifacts/contracts/NFTCollection.sol/NFTCollection.json';
import { Contract, ethers, Signer } from 'ethers';
import { Provider } from '@openmint/utils/provider';

export const Index = () => {
  const context = useWeb3React<Provider>();
  const { library } = context;

  const [contractInstance, setContractInstance] = useState<Contract | undefined>();
  const [signer, setSigner] = useState<Signer>();
  const [name, setName] = useState<String>('');

  useEffect(() => {

    const address = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
    const nftCollection = new ethers.Contract(
      address,
      NFTCollectionArtifact.abi,
      signer
    );

    setContractInstance(nftCollection);
  }, []);

  useEffect(() => {
    if(!contractInstance) return;

    const setContractName = async () => {
      try{
        console.log(await contractInstance?.name());
        setName(await contractInstance?.name());
      } catch(e){
        console.error('my error', e);
      }
    }
  
    setContractName();
  }, [contractInstance]);

  useEffect((): void => {
    if (!library) {
      setSigner(undefined);
      return;
    }

    setSigner(library.getSigner());
  }, [library]);

  return (
    <>
      <Head>
        <title>Preview NFTs</title>
      </Head>
    </>
  );
};

export default Index;

Upvotes: 0

Views: 4629

Answers (4)

Just in case - this can happen if you simply don't provide a third parameter when creating a contract object:

contract = new ethers.Contract(address, abi);

The proper way would be:

contract = new ethers.Contract(address, abi, providerOrSigner);

I wish there was a clearer error message that literally said you did not supply a signer/provider. Instead of silently accepting this on contract object creation, and then later throwing the cryptic TypeError: Cannot read properties of null (reading 'call') with a meaningless stack trace.

Upvotes: 1

Sudeep Sagar
Sudeep Sagar

Reputation: 151

This is usually seen if the signer object is invalid/undefined. Any activity with an invalid signer object like contract creation, call, send transaction, etc, will have the error: TypeError: Cannot read properties of null (reading 'call') at Contract. (node_modules@ethersproject\contracts\src.ts\index.ts:397:47)...

Upvotes: 1

Guilherme Felipe Reis
Guilherme Felipe Reis

Reputation: 918

Ok, I still do not understand the whole picture of why the following solution works, but if anyone out there is having a similar issue, this was what worked for me:

useEffect((): void => {
    if (!contractInstance) {
      return;
    }

    async function getStatus(MyContract: Contract): Promise<void> {
      const name = await MyContract.name();

      const newStatus: StatusInterface = {
        ...status,
        name
      };

      console.log('newStatus', newStatus);
      if (!isEqual(status, newStatus)) {
        setStatus(newStatus);
      }
    }

    getStatus(contractInstance);
  }, [contractInstance, status, account]);
  • Only change the state if there is a difference
  • Pass the contract as a prop for the function

My understanding is that this was a scope issue.

Upvotes: 2

Geoff
Geoff

Reputation: 850

Make sure your environment config has an account set up correctly. In my case this was happening because I had an extra WALLET_PRIVATE_KEY= line set in my .env when using ethers + hardhat.

Upvotes: 1

Related Questions