Moralis JS SDK v1.0 (migration to Ethers.js)

Thank you Erno !! Iā€™m going to try.
I also discover today that the Moralisā€™ doc has been updated regarding the Web3 Provider. Iā€™m going to make new tests.

1 Like

I assume you updated both moralis and react-moralis, right?
If so than it should work. Also note that read-only functions do return the data directly, without the need to use data.wait() (see https://docs.moralis.io/moralis-server/web3/web3#executefunction)

If you use a ā€œwriteā€ function, and use moralis v1 and react-moralis v1, and still have this issue, can you then share your code-snippet?

One more thing:
in the doc article i mentioned just in my previuous post, for paragraph " Web3.js", it is stated that this code should be in the frontend index.html :
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
Does it mean that if i want to use Ethers.js, i must remove this code ? Thank you for your advices.

Correct. You only need to include that code if you want to use web3.js

If you are using ethers.js, then you donā€™t need to include it (and you can remove it if you had it like that from before the v1 update)

1 Like
  1. I enabled Web3 with walletconnect to ethereum mainnet.
  2. Switch network to avalanche testnet.
  3. Deposit Lp
  4. Error pop up:
Error: underlying network changed (event="changed", network={"chainId":43114,"name":"unknown"}, detectedNetwork={"chainId":43113,"name":"unknown"}, code=NETWORK_ERROR, version=providers/5.5.2)
    at Logger.makeError (index.ts:225:1)
    at Web3Provider.<anonymous> (base-provider.ts:973:1)
    at Generator.next (<anonymous>)
    at fulfilled (base-provider.ts:2:1)

Enable Web3

  const connectAccount = (walletId: WalletId) => {
    let provider: MoralisType.Web3ProviderType = 'metamask'
    switch (walletId) {
      case WalletId.WALLETCONNECT:
        provider = 'walletconnect'
        break
      default:
        break
    }
    const onError = () => {
      showMessage(`Error happened on connecting to ${walletId}`, 'warning')
    }
    const onSuccess = () => {
      showMessage(`Successfully connected to ${walletId}`)
    }
    enableWeb3({ provider, onError, onSuccess })
  }


Deposit Lp

import { Contract } from 'ethers'
import { useMoralis } from 'react-moralis'
const { chainId, web3 } = useMoralis()
const handleClickSupply = async () => {
    const signer = web3.getSigner()
    const pool = new Contract(poolAddress, poolAbi, signer)
    pool.connect(signer)
    try {
      const amount = utils.parseUnits(
        depositLiquidity.token.amount,
        depositLiquidity.token.decimals,
      )
      const transaction = await pool.deposit(
        depositLiquidity.token.address,
        depositLiquidity.token.amount,
        account,
      )
      if (transaction) {
        await transaction.wait()
      }
    } catch (err) {
      console.log(err)
    }
  }
}
1 Like

@RedCabbage I encounter same error when I updated the package. What I did was to run ā€˜yarn installā€™ or do ā€˜npm installā€™ again whichever package manager you are using, and it was solved. So you can try that.

For my use case Iā€™m trying to get a private key to sign transactions on the cloud. Is there any difference in how thatā€™s done in v1.x now?

The v1 update in the sdk does not affect on how web3 works in the cloud-code. The web3 interaction in cloud-code remains the same, as described in https://docs.moralis.io/moralis-server/cloud-code/cloud-functions#web3

1 Like

Can you test with the latest version of moralis and react-moralis?

We now update the provider every time the chain is changed.

It is still not work,
I found the solution here. But I cannot set network: ā€˜anyā€™ to call moralis provider


ā€œethersā€: ā€œ^5.4.1ā€,
ā€œmoralisā€: ā€œ1.2.3ā€,
ā€œreact-moralisā€: ā€œ1.2.1ā€,

Iā€™m having the same issue, any updates on this? Iā€™m building a bridging app and need to be able to switch networks without reloading the page. Is there some way to validate if the provider has changed, or some way to force it?

Iā€™ve found a couple of options that seem to work. The first is a bit of a hack, and may be fragile.
Once you get your provider handle with
web3Provider = await Moralis.enableWeb3();
do
web3Provider.anyNetwork = true;

While this did appear to work in some of my tests, it was not consistent when multiple changes happened. It did seem to tolerate the first change though.

A better solution, I think, is to manually force a refresh of your handle whenever you expect a network change.

	await Moralis.switchNetwork(newNetwork);
	web3Provider = await Moralis.enableWeb3();

you might be able to handle the refresh using the network changed event listener, but I have not tried that.

Hope this helps

@oscar, @mloit

Fixed in v1.2.5

Added the option to set ā€˜anyā€™ network by using anyNetwork param when calling enableWeb3/authenticate:

enableWeb3({anyNetwork: true})

Please not the warning found in the linked github ( Discussion: Provider will fail if the backend network changes except for ā€œanyā€

This only affects backends that can change their network, such as MetaMask or using your own Geth instance; to get the legacy functionality, pass the string "any" as the network parameter, but please be aware that there are many edge cases your dapp should be handling that you may not be. Not using the "any" network might help flush out parts of your dapp which were previously unsafe in cases you hadnā€™t even thought of. :slight_smile:

Alternatively, depending on your dapp, when you use react, you can also use useEffect/useMemo to update the contract instance when the web3 instance updates (for example when the chain changes)

  const { Moralis, web3 } = useMoralis();

  const contract = useMemo(() => {
    if (!web3) {
      return null;
    }

    return new Moralis.web3Library.Contract(
      "0x123456",
      ABI,
      web3
    );
  }, [Moralis.web3Library, web3]);

Thanks for the quick work. It broke my ā€œfixā€ above, but thatā€™s fine. It has created a new problem though, specific to the Binance Test Network [and is tied to a bug in Metamask] where we get a web3 disconnection on a switch into the network. I was working around this by forcing a reconnect on the disconnection notice, and that worked fine until this update. Now when I switch into the test network I get an uncaught exception inside moralis.js

Uncaught TypeError: Cannot read properties of null (reading 'web3')
    at Function.value (moralis.js:5874:45)
    at InternalWeb3Provider.<anonymous> (moralis.js:5924:32)
    at InternalWeb3Provider.emit (moralis.js:70661:5)
    at InternalWeb3Provider.value (moralis.js:1572:12)
    at InjectedWeb3Connector.emit (moralis.js:70661:5)
    at InjectedWeb3Connector.value (moralis.js:27341:12)
    at i (inpage.js:1:54958)
    at l.emit (inpage.js:1:55353)
    at l._handleChainChanged (inpage.js:1:40315)
    at l._handleChainChanged (inpage.js:1:45320)

Once this error occurs, any calls to change the network return immediately with a failure because web3 no longer exists. The exception seems to be thrown after my successful reconnection happens in the ondisconnect handler. This now leaves the web3 provider handle unreliable.

I see, same happens to me, but only for the binance testnet, that is really weird.

You can set the rpc url in metamask (via settings > network) to https://data-seed-prebsc-2-s3.binance.org:8545
They have multiple rpcs, seems that not all of them are working nice with chain changes.

Will see what we can do about it, it might out of our control, but I will check.

When this situation happens, a disconnect event is fired. You could check for this event in your app and account for it.

 Moralis.onDisconnect((args) => console.log("onDisconnect", args));

Also, do you have a link to the related metamask issue?

here is my onDisconnect handlerā€¦ it does re register a listener on the new instance, but I am not seeing a disconnect event being fired, only the uncaught exception coming out of ā€˜inpageā€™. The exception seems to come about a second after the new instance is created in the old onDisconnect handler.

	unsubDisconnect = Moralis.onDisconnect(async function(error) {
		console.log("onDisconnect:",error)
		if(loggedIn === true) {
			endSession();
			console.log("Attempting to reconnect Web3");
			await Moralis.enableWeb3({anyNetwork: true}).then(function(result) {
				console.log('web3() enabled');
				web3Provider = result;
				beginSession();
			}).catch(async function() {
				await Moralis.enableWeb3({ provider: "walletconnect", anyNetwork: true }).then(function(result) {
					console.log('web3(walletconnect) enabled');
					web3Provider = result;
					beginSession();
				}).catch(function(error) {
					console.log('web3 failed', error);
				});
			});
		}
	});

and here is the sequence of events I see on the console when it happens. Note that the Registering Listeners comes from beginSession(), and is where the onDisconnect listener is registered to the new instance.

onDisconnect: Error: MetaMask: Disconnected from chain. Attempting to connect.
    at l._handleDisconnect (inpage.js:1:39598)
    at l._handleDisconnect (inpage.js:1:43404)
    at l._handleChainChanged (inpage.js:1:40205)
    at l._handleChainChanged (inpage.js:1:45320)
    at o.<anonymous> (inpage.js:1:37771)
    at i (inpage.js:1:54958)
    at o.emit (inpage.js:1:55498)
    at inpage.js:1:54022
    at f.write [as _write] (inpage.js:1:54045)
    at w (inpage.js:17:29414)
main.js:842 Deregestering Event Listeners
main.js:822 Attempting to reconnect Web3
main.js:824 web3() enabled
main.js:781 Regestering Event Listeners
inpage.js:1 Uncaught TypeError: Cannot read properties of null (reading 'web3')
    at Function.value (moralis.js:5874:45)
    at InternalWeb3Provider.<anonymous> (moralis.js:5924:32)
    at InternalWeb3Provider.emit (moralis.js:70661:5)
    at InternalWeb3Provider.value (moralis.js:1572:12)
    at InjectedWeb3Connector.emit (moralis.js:70661:5)
    at InjectedWeb3Connector.value (moralis.js:27341:12)
    at i (inpage.js:1:54958)
    at l.emit (inpage.js:1:55353)
    at l._handleChainChanged (inpage.js:1:40315)
    at l._handleChainChanged (inpage.js:1:45320)
value @ moralis.js:5874
(anonymous) @ moralis.js:5924
emit @ moralis.js:70661
value @ moralis.js:1572
emit @ moralis.js:70661
value @ moralis.js:27341
i @ inpage.js:1
emit @ inpage.js:1
_handleChainChanged @ inpage.js:1
_handleChainChanged @ inpage.js:1
(anonymous) @ inpage.js:1
i @ inpage.js:1
emit @ inpage.js:1
(anonymous) @ inpage.js:1
write @ inpage.js:1
w @ inpage.js:17
(anonymous) @ inpage.js:17
y.write @ inpage.js:17
g @ inpage.js:17
d @ inpage.js:8
s.emit @ inpage.js:8
_ @ inpage.js:17
v @ inpage.js:17
w.push @ inpage.js:17
_write @ inpage.js:1
w @ inpage.js:17
(anonymous) @ inpage.js:17
y.write @ inpage.js:17
g @ inpage.js:1
d @ inpage.js:8
s.emit @ inpage.js:8
_ @ inpage.js:1
v @ inpage.js:1
w.push @ inpage.js:1
_onData @ inpage.js:1
_onMessage @ inpage.js:1
setTimeout (async)
i @ inpage.js:1
emit @ inpage.js:1
_handleChainChanged @ inpage.js:1
_handleChainChanged @ inpage.js:1
(anonymous) @ inpage.js:1
i @ inpage.js:1
emit @ inpage.js:1
(anonymous) @ inpage.js:1
write @ inpage.js:1
w @ inpage.js:17
(anonymous) @ inpage.js:17
y.write @ inpage.js:17
g @ inpage.js:17
d @ inpage.js:8
s.emit @ inpage.js:8
_ @ inpage.js:17
v @ inpage.js:17
w.push @ inpage.js:17
_write @ inpage.js:1
w @ inpage.js:17
(anonymous) @ inpage.js:17
y.write @ inpage.js:17
g @ inpage.js:1
d @ inpage.js:8
s.emit @ inpage.js:8
_ @ inpage.js:1
v @ inpage.js:1
w.push @ inpage.js:1
_onData @ inpage.js:1
_onMessage @ inpage.js:1
postMessage (async)
_postMessage @ contentscript.js:1
_write @ contentscript.js:1
w @ contentscript.js:1
(anonymous) @ contentscript.js:1
y.write @ contentscript.js:1
g @ contentscript.js:17
h @ contentscript.js:8
s.emit @ contentscript.js:8
_ @ contentscript.js:17
v @ contentscript.js:17
w.push @ contentscript.js:17
_write @ contentscript.js:17
w @ contentscript.js:17
(anonymous) @ contentscript.js:17
y.write @ contentscript.js:17
g @ contentscript.js:17
h @ contentscript.js:8
s.emit @ contentscript.js:8
_ @ contentscript.js:17
v @ contentscript.js:17
w.push @ contentscript.js:17
_write @ contentscript.js:17
w @ contentscript.js:17
(anonymous) @ contentscript.js:17
y.write @ contentscript.js:17
g @ contentscript.js:17
h @ contentscript.js:8
s.emit @ contentscript.js:8
_ @ contentscript.js:17
v @ contentscript.js:17
w.push @ contentscript.js:17
_onMessage @ contentscript.js:8
(anonymous) @ contentscript.js:8
Show 39 more frames

here is the Metamask report, itā€™s not the exact issue, but I suspect it stems from the same root cause. My post is at the end mentioning this issue specifically.

1 Like

Seems that metamask is atleast reaconnecting, if it fails on the binance rpc. Now we check for this specific error. If so, we will not fire a disconnect event. That should do the trick.

Update to 1.2.6 for this fix

At least in my test environment it works perfectly with the binance testnet. It does take a bit longer than a ā€˜normalā€™ change of networks though it seems

thanks, 'll give it a goā€¦ doesnā€™t matter if it takes a bit longer, I have a delay built in after the change to allow for some reconnection. I vaguely remember there being a isWeb3enabled call or something similar, but canā€™t seem to find it now. maybe something like that could be used to check the ready state of the provider?

Yep, you can use Moralis.isWeb3Enabled()

Or if you use hooks you can use isWeb3Enabled or any of the following properties to check if everytihing is allright:

const {
    isWeb3Enabled,
    isWeb3EnableLoading,
    web3EnableError,
    chainId,
    network,
    connectorType,
    account,
} = useMoralis()
1 Like