Moralis React enableWeb3

In documentation Moralis-React says that web3 will automatically be ebabled when user logs in. But it doesn’t. How to get acces to functions like web3.eth.getAccounts or to work with ABIs?

import { useMoralis } from "react-moralis";

export default function Hello() {
 const { isWeb3Enabled } = useMoralis();

 if (!isWeb3Enabled) {
    alert("It's not"); //and i get it
  }
}

Whole app is wrapped by moralisprovider, what’s the problem?

You need to call enable()

1 Like

Thanks. It works with enable(). But there is a mistake in the documentation.

2 Likes

Thanks for the feedback. This was changed a little ago. Now you need to call the function manually. will change it in the documentation :slight_smile:

1 Like

Alright you all are obviously expert ReactJS coders. I am also an expert…at Fortran. Many things are lost in translation. I’ve many MANY questions about enabling Moralis’ web3 in a ReactJS and they’re all going to seem quite stupid around here. So here goes.

All I want to do is retrieve an ETH balance for a known (decidedly non-zero) test address. Let’s hard-code the address and worry about retrieving it from import {user } from useMoralis(); later.

Pseudocode:
-Enable web3.
-Retrieve balance.
-Translate from wei to ETH.
-Display balance.

Complications:
-web3 calls seem to need an ‘await’? So…I have to call them in an async function?
-I’m using other useMoralis() hooks elsewhere in my project that seem to interfere with what I’m trying to do here (error messages I’m getting are in the comments where I think they’re being caused.

THIS…is obviously NOT the way to do this. So my question is: so what is?
I’m expecting something in 10 lines of code or less for such a simple task.

Any and all tips, pointers, and help will be appreciated.

import { Text } from "@chakra-ui/react";
import { useMoralis } from "react-moralis";

export const Balance = () => {
  const { enableWeb3, isWeb3Enabled, web3 } = useMoralis();

  if (!isWeb3Enabled) {
    console.log("Balance() is enabling web3...");
    // Warning: Cannot update a component ('MoralisProvider')
    // while rendering a different component ('Balance').
    // To locate the bad setState() call inside 'balance'
    //follow the stack trace as described in <gibberish>
    enableWeb3();
  } else {
    console.log("Balance() found web3 in an enabled state.");
  }
  console.log("web3 should be enabled now.");

  const getBalance = async () => {
    // Had to be inside an async because web3 needs 'await's?
    // Otherwise all this would be in local component scope.
    console.log("getBalance() is getting Vitalik's balance...");
    let value = await web3.eth.getBalance(
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    );
    // This is as far as it gets.  I never get the following:
    console.log(
      "getBalance() is converting Vitalik's balance from " +
        value +
        "wei into ETH..."
    );
    value = await web3.utils.fromWei(value);
    console.log("Vitalik's balance is: " + value + "ETH.");
    return value;
  };

  // Attempting to pull getBalance result into component's scope...
  // But this just makes the pile of error pancakes taller.
  const balance = getBalance(); 

  // Warning: Functions are not valid as a React child.
  return <Text>Balance:{balance}</Text>;
};

To activate web3 i use this.

useEffect(() => {
  if (!isWeb3Enabled) {
     enableWeb3();
  }
  }, [web3.currentProvider]);

You should use more setState functions. For example:

const [balance, setBalance] = useState();
useEffect(() => {
  async function getChainsData() {
    if (web3.currentProvider) {
      setBalance(await web3.eth.getBalance(
      "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
    ));
    }
  }
  getChainsData();
}, [web3]);

balance ? console.log("Balance is"+ balance) : console.log("Balance 0");

Something like that, but could be wrong

also maybe you should add then useEffect which will listen on changes on balance state and rerender elements which use balance state

Thank you kindly, @Yomoo. With your tips and a few tweaks I was able to get it running. currently:

import { Text } from "@chakra-ui/react";
import { useMoralis } from "react-moralis";
import { useState, useEffect } from "react";

export const Balance = () => {
  const { enableWeb3, isWeb3Enabled, web3 } = useMoralis();
  const [balance, setBalance] = useState(-1);
  useEffect(() => {
    async function getChainsData() {
      if (!isWeb3Enabled) {
        enableWeb3();
      }
      if (web3.currentProvider) {
        setBalance(
          web3.utils.fromWei(
            await web3.eth.getBalance(
              "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
            )
          )
        );
      } else {
        console.log(
          "web3.currentProvider is not defined.  Skipping getBalance call."
        );
      }
    }
    getChainsData();
  }, [enableWeb3, isWeb3Enabled, web3]);

  console.log("Retrieved balance: " + balance + "ETH");
  // Warning: Functions are not valid as a React child.
  return <Text>Balance: {balance} ETH</Text>;
};

image

For my next trick: parameterizing the address. I need to figure out how to pull the current address out of the current Moralis user and stuff it into this component.
Cheers!

const { user } = useMoralis();

const [wallet, setWallet] = useState();

setWallet(user.attributes.ethAddress);

console.log(wallet)

Before setWallet you should add checker is “Authenticated”

1 Like

This is the function as I want it to be written:

import { Text } from "@chakra-ui/react";
import { useMoralis } from "react-moralis";
import { useState, useEffect } from "react";

export const Balance = () => {
  const [balanceETH, setBalanceETH] = useState();
  const { Moralis } = useMoralis();
  useEffect(() => {
    async function getBalance() {
      !Moralis.Web3.isWeb3Enabled && Moralis.Web3.enableWeb3();
      !Moralis.User.isAuthenticated && Moralis.Web3.authenticate();
      setBalanceETH(Moralis.User.getERC20());
    }
    getBalance();
  }, [Moralis.User, Moralis.Web3]);
  return <Text>Balance: {balanceETH} ETH</Text>;
};

And it compiles. However at runtime I get the following complaints:

  • Moralis.Web3.enableWeb3 is not a function
  • Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    (among others, but will probably clear up if I can find enableWeb3 within the Moralis object.

It seems to be a matter of locating and identifying the various functions on the Moralis object and its components objects.

I dont understand this logic.

!Moralis.Web3.isWeb3Enabled && Moralis.Web3.enableWeb3();
!Moralis.User.isAuthenticated && Moralis.Web3.authenticate();

Don’t use [Moralis.User, Moralis.Web3] as a dependency in UseEffect hook, because in the moment of initlization methods .User and .Web3 may not have time to initialize.

Why the function getBalance() is async? You dont use await inside.

You should use something like this. But i dont really remember synax of Moralis and probably you should check if isWeb3Enabled and only then setBalanceETH. Because it usualy takes a time to enable web3

import { Text } from "@chakra-ui/react";
import { useMoralis } from "react-moralis";
import { useState, useEffect } from "react";

export const Balance = () => {
  const [balanceETH, setBalanceETH] = useState();
  const { authenticate, isAuthenticated,user, web3, enableWeb3, isWeb3Enabled, Moralis } = useMoralis();
  useEffect(() => {
    function enableWeb3() {
      if (!isWeb3Enabled) {
        enableWeb3();
      }
    }
    enableWeb3().then(() => setBalanceETH(Moralis.User.getERC20());
  }, [web3]);
  return <Text>Balance: {balanceETH} ETH</Text>;
};

You should read https://github.com/MoralisWeb3/react-moralis

It’s shorthand for
if (!Moralis.Web3.isWeb3Enabled) { Moralis.Web3.enableWeb3(); } and so on.

  • Why not just call enableWeb3 regardless and let it determine if it needs to do anything or just return?

  • That and wherever getERC20() comes from end up as dependencies to the useEffect()

So:

import { useMoralis } from "react-moralis";
import { useState, useEffect } from "react";

export const Balance = () => {
  const [balanceETH, setBalanceETH] = useState();
  const { enableWeb3, Moralis } = useMoralis();
  useEffect(() => {
    function fetchBalance() {
      enableWeb3().then(setBalanceETH(Moralis.User.getERC20()));
    }
    fetchBalance();
  }, [Moralis.User, enableWeb3]);
  return <>Balance: {balanceETH} ETH</>;
};

Which would be beautiful…except:

TypeError: Moralis.User.getERC20 is not a function

I have indeed read the react-moralis docs both on npm and on GitHub. The documentation is new so it’s written for experts in the project, which I obviously ain’t. There are things missing like const { Moralis } = useMoralis(). And there are things “overstated” like "getERC20() is a function of User" (that one I heard around here, also not in the docs). There’s no listing of simple practical functions like “how do I get my end user’s ETH balance?” Expert writer’s can’t comprehend the totality of disorientation noobs like me really experience. So I hope I’m contributing at least that much perspective. Stairways to heaven are lovely, but they need to touch Earth somewhere…

Per your suggestion I’m rummaging through the actual code now to see what’s REALLY in the tin.

Day 3 of “use Moralis, it’s plug-and-play” and I haven’t got a reliable “fetch my ETH balance” function working yet in React. But to be fair most my struggle is with React.

1 Like

Anywho…I wasn’t having a Moralis issue. I was having a bad ReactJSion. Now .then it works.

import { Text } from "@chakra-ui/react";
import { useMoralis } from "react-moralis";
import { useEffect, useState } from "react";

export const Balance = () => {
  const { isAuthenticated, Moralis } = useMoralis();
  const [balance, setBalance] = useState(-1);

  useEffect(() => {
    if (isAuthenticated) {
      Moralis.Web3.getERC20().then((balanceObject) => {
        setBalance(balanceObject.balance);
      });
    }
  }, [isAuthenticated, Moralis, setBalance]);

  return <Text>Balance: {balance} Wei</Text>;
};