How can i handle this error - Moralis Moralis.enableWeb3() already has been called, but is not finished yet

I getting this error, when calling multiple function at same time… some time if once executed code is not completed… How can i handle this?
If i am trying to use try catch - i am getting this error
Error: Missing web3 instance, make sure to call Moralis.enableWeb3() or Moralis.authenticate()

As mentioned, make sure you call Moralis.enableWeb3() or with an authenticated user authenticating Moralis.authenticate() .

Do you have code snippet of where you are calling enableWeb3?

Hi i have created a class where i am writing all web3 execution code that named web3Services.js, and another page index.js in click item i am calling one of my function Buy item…
so my web3Services Code is like this…remember this is master code…i want my developer call from here…

case :- sometime …user is already connected their wallet with my app and sometime they are not connected… and trying to call buy function directly…so i want that time connect first and execute next code,…

import { ethers } from "ethers";

export const Moralis = require('moralis');

/*
* You can write all web3 based call here
* so, no need to rewrite in every page, like mint function
*/
export class Web3Service {

    /*
    // Better practice to use this thing from .env, find solution
    CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS
    SIGNER_KEY = process.env.PRIVATE_KEY
    CHAIN_ID = process.env.CHAIN_ID
    */
    CONTRACT_ADDRESS = "XXXXXX"
    PRIVATE_KEY = "XXXXXX"
    CHAIN_ID = 4
    CHAIN_HASH = "0x4"

    //Connected User Data

    getWei = async (price) => {
        return Moralis.Units.ETH(price, 18)
    }

    enableWeb3 = async () => {
        try{
            await Moralis.enableWeb3(); 
        } catch(err){
            console.error("Error enableWeb3", err)
        }
    }

    //check if web3 is enable, either enable it
    //Call this function always
    isWeb3Enable = async () => {
        if(Moralis.isWeb3Enabled() == false) {
            try{
                await Moralis.enableWeb3();
            } catch(err){
                console.error("Error isWeb3Enable", err)
            }
        }
    }

    //return connected user and chain id
    getWallet = async (providerName="metamask", verifyChain=false) => {
        try {
            if(verifyChain){
                await this.verifyChain()
            }
            const web3Provider = await Moralis.enableWeb3({ provider: providerName });
            if(web3Provider.provider.constructor.name === "WalletConnectProvider"){
                return [web3Provider.provider.accounts[0], ethers.utils.hexValue(web3Provider.provider.chainId), providerName]
            }
            return [web3Provider.provider.selectedAddress, web3Provider.provider.chainId, providerName]
        } catch(err) {
            console.error("Error getWallet: Web3 Initialization Execption", err)
            return []
        }
    }

    //return web3Provider 
    getChain = async () => {
        try {
            const chainId = await Moralis.chainId;
            return chainId
        } catch(err) {
            console.error("Error getChain: Web3 Initialization Execption", err)
            return null
        }
    }

    verifyChain = async () => {
        const chainId = await Moralis.chainId;
        if(parseInt(chainId)!=this.CHAIN_ID){
            await this.switchChain(this.CHAIN_HASH)
        }
    }

    //return web3Provider 
    switchChain = async (chainId) => {
        try {
            await Moralis.switchNetwork(chainId);
            return chainId
        } catch(err) {
            console.error("Error switchChain: Web3 Initialization Execption", err)
            return chainId
        }
    }

    //execute when user change acccount on metamask
    metamaskAccountChange = async () => {
        ethereum.on('accountsChanged', (accounts) => {
            return accounts
        });
        return null
    }

    //execute when user change chain on metamask
    metamaskChainChange = async () => {
        ethereum.on('chainChanged', (chain) => {
            return chain
        });
        return null
    }

    isMetamaskUnlocked = async () => {
        ethereum._metamask.isUnlocked().then((res)=> {
            console.log("is metamask connected: ", res)
            return res
        })
    }

    /*
    *   Return current gas price 
    */
    getGasPrice = async (provider="metamask") => {
        const web3Provider = await Moralis.enableWeb3({ provider: provider });
        return await web3Provider.getGasPrice();
    }

    //function to check if contract is approved to access token
    // You can modify condition as per your need
    isApprovedForAll = async (account, operator, provider = "metamask") => {

        const ABI =  [{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

        const readOptions = {
            contractAddress: this.CONTRACT_ADDRESS,
            chainId: this.CHAIN_ID,
            functionName: "isApprovedForAll",
            abi: ABI,
            params: {
                account: account, 
                operator: operator
            }
        };
        await this.enableWeb3()
        return await Moralis.executeFunction(readOptions);
    }

    //function to approve to access token
    // You can modify condition as per your need
    // if operator address is constant, no need to pass in argument, but declare here
    setApprovalForAll = async (account, operator, approved = true, providerName = "metamask") => {

        if(!this.isApprovedForAll(account, operator)){
            const ABI =  [{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]

            const writeOptions = {
                contractAddress: this.CONTRACT_ADDRESS,
                chainId: this.CHAIN_ID,
                functionName: "setApprovalForAll",
                abi: ABI,
                params: {
                    operator: operator, 
                    approved: approved
                }
            };
            const receipt  = await Moralis.executeFunction(writeOptions)
            await receipt.wait()
            return receipt
        } else {
            return "already aproved"
        }
    }

    getTokenNo = async (creator, amount, nonce, collectionId) => {
        //first verify .. selected chain is as above define
        const readOptions = {
            contractAddress: this.CONTRACT_ADDRESS,
            functionName: "genTokenHash",
            abi: [{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_collectionId","type":"string"}],"name":"genTokenHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],
            params: {
                _creator: creator,
                _amount: amount,
                _nonce: nonce,
                _collectionId: collectionId
            }
        };
        await this.enableWeb3()
        const message = await Moralis.executeFunction(readOptions);
        //console.log(message, "Token Details")
        return message
    }

    //function to approve to access token
    // You can modify condition as per your need
    // if operator address is constant, no need to pass in argument, but declare here
    buy = async (tokenNo, price, amount, buyer, seller, paytoken, nonce, tuple, trade_type, providerName = "metamask") => {
        try{
            const ABI = [{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_buyer","type":"address"},{"internalType":"address payable","name":"_seller","type":"address"},{"internalType":"address","name":"_pToken","type":"address"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"components":[{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"collectionId","type":"string"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"blockTime","type":"uint256"}],"internalType":"struct Marketplace.Token","name":"_token","type":"tuple"},{"internalType":"uint8","name":"_tradeType","type":"uint8"}],"name":"buyAndAccept","outputs":[],"stateMutability":"payable","type":"function"}];

            const writeOptions = {
                contractAddress: this.CONTRACT_ADDRESS,
                functionName: "buyAndAccept",
                abi: ABI,
                params: {
                    _tokenId: tokenNo,
                    _price: price,
                    _amount: amount,
                    _buyer: buyer,
                    _seller: seller,
                    _pToken: paytoken,
                    _nonce: nonce, //read from db
                    _token: tuple,
                    _tradeType: trade_type
                },
                msgValue: paytoken != "0x0000000000000000000000000000000000000000"? 0: price * amount
            };
            await this.enableWeb3()
            const tx = await Moralis.executeFunction(writeOptions);
            console.log("Before wait: ", tx)
            await tx.wait();
            return [true, tx ]
        } catch(err) {
            return [false, err ]
        }
    }
}

My index.html code is like this

const buy = async () => {

    //always call this first
    //await web3Service.enableWeb3()
    await connectWallet() //check here ..first trying to login

    const paytoken = "0x0000000000000000000000000000000000000000"
    const trade_type = 0
    const price = await web3Service.getWei(0.001) //check here
    const amount = 4
    const seller = "xxxxxxxxxxxxxxxxxxx"
    const buyer = wallet
    const collectionId = "xxxxxxxxxxxxxxxxxx"
    const nonce = new Date().getTime()
    const tokenArr = await web3Service.getTokenNo(seller, amount, nonce, collectionId) //chjeck here
    const tokenBlock = tokenArr[0]
    const tokenTime = tokenArr[1]
    const tokenNo = tokenArr[2]
    const tuple = [
      "https://gateway.ipfs.io/ipfs/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      amount,
      collectionId,
      seller,
      tokenBlock,
      tokenTime
    ]

    web3Service.buy(tokenNo, price, amount, buyer, seller, paytoken, nonce, tuple, trade_type).then((res)=> {
      if(res[0]){
        console.log("transaction success", res[1])
        setMsg(res[1])
      } else {
        console.error("transaction failed", res[1])
        setMsg(res[1])
      }
    }).catch((err)=>{
      console.error(err)
      setMsg(err)
    })

  }

and login code is in index.html

const connectWallet = async () => {
    await web3Service.enableWeb3()
    web3Service.getWallet(selectedProvider).then(async (connection) => {
      if(connection.length > 0){
        setWallet(connection[0])
        setChain(connection[1])
        setProvider(connection[2])
        setMsg(`Connect wallet address is ${connection[0]} & chain id ${connection[1]} & provider is ${connection[2]}`)
      }
    })
  }

and this my useEffect

useEffect(() => { 
    //code to change account if 
    web3Service.metamaskAccountChange().then((res)=>{ setWallet(res) })
    web3Service.metamaskChainChange().then((res)=>{ setChain(res) })
    web3Service.isMetamaskUnlocked().then((res)=> {
      if(provider === "metamask" && res === false){
        disconnect()
      }
    });
  }, [])

how can i manage code , so my frontend team can call these function directly on their code…instead of wrting same thing everytime… i am getting these error - first
Error enableWeb3 Error: Cannot execute Moralis.enableWeb3(), as Moralis Moralis.enableWeb3() already has been called, but is not finished yet
second in same call
Uncaught (in promise) Error: Missing web3 instance, make sure to call Moralis.enableWeb3() or Moralis.authenticate()
if i have already called…why is it asking for again execute that function???

You can check if web3 is enabled with Moralis.isWeb3Enabled() before you enableWeb3

can you make a minimal code example that replicates this error?

I don’t know how to consistently replicate it

Minimal code, Okay check this
in index.js, i have written this on page load

step 1 - in page load

//some required code in page laod 
  useEffect(() => { 
    //code to change account if 
    web3Service.isWeb3Enable(); //here i have enable web3 instance
    web3Service.metamaskAccountChange().then((res)=>{ setWallet(res) }) //this contains metamask docs code
    web3Service.metamaskChainChange().then((res)=>{ setChain(res) }) //this contains metamask docs code
    web3Service.isMetamaskUnlocked().then((res)=> {
      if(provider === "metamask" && res === false){
        disconnect()
      }
    });
  }, [])

Now my isWeb3Enable code is

//check if web3 is enable, either enable it
    //Call this function always
    isWeb3Enable = async () => {
        if(Moralis.isWeb3Enabled() == false) {
            try{
                await this.enableWeb3()
            } catch(err){
                console.error("Error isWeb3Enable", err)
            }
        }
    }

Now i am calling buy function…which execute

/*
  * Here need to read data from database
  */
  const buy = async () => {

    //verify selected chain must be 0x4 in live 0x1
    await web3Service.verifyChain()
    //always call this first
    //await web3Service.enableWeb3()
    await connectWallet() //because i need connected user... below called buyer, useState wallet, so i will login
    //write as per your need
    const paytoken = "0x0000000000000000000000000000000000000000"
    const trade_type = 0
    const price = await web3Service.getWei(0.001)
    const amount = 4
    const seller = "0x00000000000000000000000000000000"
    const buyer = wallet //value set on connectWallet
    const collectionId = "00000000000000000000"
    const nonce = new Date().getTime()
    const tokenArr = await web3Service.getTokenNo(seller, amount, nonce, collectionId)
    const tokenBlock = tokenArr[0]
    const tokenTime = tokenArr[1]
    const tokenNo = tokenArr[2]
    const tuple = [
      "https://gateway.ipfs.io/ipfs/00000000000000000000000000",
      amount,
      collectionId,
      seller,
      tokenBlock,
      tokenTime
    ]

    web3Service.buy(tokenNo, price, amount, buyer, seller, paytoken, nonce, tuple, trade_type).then((res)=> {
      if(res[0]){
        console.log("transaction success", res[1])
        setMsg(`Success transaction no. is ${res[1]}}`)
      } else {
        console.error("transaction failed", res[1])
        setMsg('Transaction is failed, retry.')
      }
    }).catch((err)=>{
      console.error(err)
      setMsg(err)
    })

  }

i need this connect wallet to verify or read connected user wallet address… this line ( await connectWallet()), inside this function, i am saving setWallet(ā€œit returned wallet addressā€)…this address i have to pass to buyer variable above…

Step 2: web3Service.js

enableWeb3 = async () => {
        await Moralis.enableWeb3(); 
    }

    //check if web3 is enable, either enable it
    //Call this function always
    isWeb3Enable = async () => {
        if(Moralis.isWeb3Enabled() == false) {
            try{
                await this.enableWeb3()
            } catch(err){
                console.error("Error isWeb3Enable", err)
            }
        }
    }

//to get connected user
//return connected user and chain id
    getWallet = async (providerName="metamask", verifyChain=false) => {
        try {
            if(verifyChain){
                await this.verifyChain()
            }
            const web3Provider = await Moralis.enableWeb3({ provider: providerName });
            if(web3Provider.provider.constructor.name === "WalletConnectProvider"){
                return [web3Provider.provider.accounts[0], ethers.utils.hexValue(web3Provider.provider.chainId), providerName]
            }
            return [web3Provider.provider.selectedAddress, web3Provider.provider.chainId, providerName]
        } catch(err) {
            console.error("Error getWallet: Web3 Initialization Execption", err)
            return []
        }
    }


    verifyChain = async () => {
        const chainId = await Moralis.chainId;
        if(parseInt(chainId)!=this.CHAIN_ID){
            await this.switchChain(this.CHAIN_HASH)
        }
    }

//return web3Provider 
    switchChain = async (chainId) => {
        try {
            await Moralis.switchNetwork(chainId);
            await this.enableWeb3() //need to call due to relogin after network change
            return chainId
        } catch(err) {
            console.error("Error switchChain: Web3 Initialization Execption", err)
            return chainId
        }
    }

//execute when user change acccount on metamask
    metamaskAccountChange = async () => {
        ethereum.on('accountsChanged', (accounts) => {
            return accounts
        });
        return null
    }

    //execute when user change chain on metamask
    metamaskChainChange = async () => {
        ethereum.on('chainChanged', (chain) => {
            return chain
        });
        return null
    }

    isMetamaskUnlocked = async () => {
        ethereum._metamask.isUnlocked().then((res)=> {
            console.log("is metamask connected: ", res)
            return res
        })
    }
getTokenNo = async (creator, amount, nonce, collectionId) => {
        //first verify .. selected chain is as above define
        const readOptions = {
            contractAddress: this.CONTRACT_ADDRESS,
            functionName: "genTokenHash",
            abi: [{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_collectionId","type":"string"}],"name":"genTokenHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],
            params: {
                _creator: creator,
                _amount: amount,
                _nonce: nonce,
                _collectionId: collectionId
            }
        };
        const message = await Moralis.executeFunction(readOptions);
        //console.log(message, "Token Details")
        return message
    }
//function to approve to access token
    // You can modify condition as per your need
    // if operator address is constant, no need to pass in argument, but declare here
    buy = async (tokenNo, price, amount, buyer, seller, paytoken, nonce, tuple, trade_type, providerName = "metamask") => {
        try{
            const ABI = [{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_buyer","type":"address"},{"internalType":"address payable","name":"_seller","type":"address"},{"internalType":"address","name":"_pToken","type":"address"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"components":[{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"collectionId","type":"string"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"blockTime","type":"uint256"}],"internalType":"struct Marketplace.Token","name":"_token","type":"tuple"},{"internalType":"uint8","name":"_tradeType","type":"uint8"}],"name":"buyAndAccept","outputs":[],"stateMutability":"payable","type":"function"}];

            const writeOptions = {
                contractAddress: this.CONTRACT_ADDRESS,
                functionName: "buyAndAccept",
                abi: ABI,
                params: {
                    _tokenId: tokenNo,
                    _price: price,
                    _amount: amount,
                    _buyer: buyer,
                    _seller: seller,
                    _pToken: paytoken,
                    _nonce: nonce, //read from db
                    _token: tuple,
                    _tradeType: trade_type
                },
                msgValue: paytoken != "0x0000000000000000000000000000000000000000"? 0: price * amount
            };
            const tx = await Moralis.executeFunction(writeOptions);
            console.log("Before wait: ", tx)
            await tx.wait();
            return [true, tx.hash ]
        } catch(err) {
            return [false, err ]
        }
    }

i have removed enableWeb3…so my first error in page load…
Error isWeb3Enable Error: Cannot execute Moralis.enableWeb3(), as Moralis Moralis.enableWeb3() already has been called, but is not finished yet
same on buy also

in useEffect, ihave not used await withy web3Service.isWeb3Enable();…because…i dont want to wait but run this on background… am i bad in react programming?..i have never faced this issues on angular and vanilla js…
also i want to update here…sometime buy function is working…but if i will refresh and again execute buy,i will get enable web3 require based error…you can see in login i am running web3…

minimal code…if i have to execute one function only…its working fine…
issue is only when i need to relogin or if i am calling web3Enable again as per requirements …if i will write this code in one place so i can use this on every projects…what in erc721 and erc1155 …there is only…mint, transfer, approve is mostly used function… need to change only abi in every project

I think that this was solved in discord (by not making so many calls to enableWeb3 at the same time), do you still have issues?

Hi, I checked…if i am writing enable web3 in page load…it is working fine…but need to be write once only…so now in my code…in use effect…i am writing this enable web3 …and then only running other codes…

Sorry i am waiting for issue if again i will face… bcz i have already done code like this…but i had faced no web3 enable issue … i am just checking when i had faced that error…

it works fine now for you?

yes…its okay fr now

1 Like