web3modal
web3modal copied to clipboard
WalletConnect - Provider not set or invalid
I'm having issues running this web3modal for mobile interaction via WalletConnect.
Desktop Metamask/Coinbase works etc it's simply when I use the QR code and log in using WalletConnect that I can't run any functions.
It pulls the correct address and displays as expected but when I try to use the provider I get the error
Uncaught (in promise) Error: Provider not set or invalid
The function that is running as a test is:
//variables from previous parts of the code:
const contract_address = "xxx";
var contractInterface = new web3.eth.Contract(ABI, contract_address)
const ABI = myABI is here
export const eatBeans = async () => {
let address = selectedAccount
if (address) {
await contractInterface.methods.eatBeans().send({ from: address })
await fetchAccountData()
}
}
the full code is here
import React from "react";
import {
chakra,
Box,
Flex,
useColorModeValue,
VisuallyHidden,
HStack,
useDisclosure,
VStack,
IconButton,
CloseButton,
useColorMode,
Avatar,
Button,
} from "@chakra-ui/react";
import { AiOutlineMenu } from "react-icons/ai";
import { FaMoon, FaSun } from "react-icons/fa";
import Web3EthContract from "web3-eth-contract";
import Web3 from "web3";
import Web3Modal from "web3modal";
import WalletConnectProvider from "@walletconnect/web3-provider";
import WalletLink from "walletlink";
//const EvmChains = window.EvmChains;
const INFURA_ID = "XXXX";
const providerOptions = {
walletconnect: {
package: WalletConnectProvider, // required
options: {
infuraId: INFURA_ID, // required
rpc: {
56: "https://bsc-dataseed.binance.org/",
},
},
},
walletlink: {
package: WalletLink, // Required
options: {
appName: "XXXX", // Required
infuraId: "", // Required unless you provide a JSON RPC url; see `rpc` below
rpc: "https://bsc-dataseed.binance.org/", // Optional if `infuraId` is provided; otherwise it's required
chainId: 56, // Optional. It defaults to 1 if not provided
appLogoUrl: null, // Optional. Application logo image URL. favicon is used if unspecified
darkMode: true, // Optional. Use dark theme, defaults to false
},
},
};
let provider
const web3 = new Web3(Web3.provider);
// Chosen wallet provider given by the dialog window
// Address of the selected account
let selectedAccount;
const web3Modal = new Web3Modal({
network: "mainnet", // optional
cacheProvider: false, // optional
providerOptions, // required
});
console.log("Initializing example");
console.log("WalletConnectProvider is", WalletConnectProvider);
async function fetchAccountData() {
const provider = await web3Modal.connect();
const web3 = new Web3(provider);
console.log("web", web3);
Web3EthContract.setProvider(provider);
console.log("Web3 from FetchAccountData worked", web3);
console.log("Refresh account data provider = " + await provider)
if (window.ethereum) {
try {
// check if the chain to connect to is installed
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x38' }], // chainId must be in hexadecimal numbers
});
} catch (error) {
// This error code indicates that the chain has not been added to MetaMask
// if it is not, then install it into the user MetaMask
if (error.code === 4902) {
try {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: '0x38',
rpcUrl: 'https://bsc-dataseed.binance.org/',
},
],
});
} catch (addError) {
console.error(addError);
}
}
console.error(error);
}
} else {
// if no window.ethereum then MetaMask is not installed
console.log('no window.ethereum then MetaMask is not installed');
}
// Get list of accounts of the connected wallet
const accounts = await web3.eth.getAccounts();
// MetaMask does not give you all accounts, only the selected account
console.log("Got accounts", accounts);
selectedAccount = accounts[0];
document.querySelector("#selected-account").textContent = selectedAccount;
// Get a handl
//const template = document.querySelector("#template-balance");
// Purge UI elements any previously loaded accounts
// Go through all accounts and get their ETH balance
const rowResolvers = accounts.map(async (address) => {
const balance = await web3.eth.getBalance(address);
// ethBalance is a BigNumber instance
// https://github.com/indutny/bn.js/
const ethBalance = web3.utils.fromWei(balance, "ether");
const humanFriendlyBalance = parseFloat(ethBalance).toFixed(4);
// Fill in the templated row and put in the document
//clone.querySelector(".address").textContent = address;
document.querySelector(".balance").textContent = humanFriendlyBalance;
//accountContainer.appendChild(clone);
});
// Because rendering account does its own RPC commucation
// with Ethereum node, we do not want to display any results
// until data for all accounts is loaded
await Promise.all(rowResolvers);
// Display fully loaded UI for wallet data
if(document.querySelector("#prepare")){
document.querySelector("#prepare").style.display = "none";
document.querySelector("#connected").style.display = "block";
document.querySelector("#templates").style.display = "block";
}
}
/**
* Fetch account data for UI when
* - User switches accounts in wallet
* - User switches networks in wallet
* - User connects wallet initially
*/
const refreshAccountData = async () => {
// const provider = await web3Modal.connect();
// const web3 = new Web3(provider);
// console.log("web loaded from refresh data", web3);
// Web3EthContract.setProvider(provider);
// If any current data is displayed when
// the user is switching acounts in the wallet
// immediate hide this data
if( document.querySelector("#connected") ){
document.querySelector("#connected").style.display = "none";
document.querySelector("#prepare").style.display = "block";
}
// Disable button while UI is loading.
// fetchAccountData() will take a while as it communicates
// with Ethereum node via JSON-RPC and loads chain data
// over an API call.
if(document.querySelector("#btn-connect")){
document.querySelector("#btn-connect").setAttribute("disabled", "disabled")
await fetchAccountData(provider);
document.querySelector("#btn-connect").removeAttribute("disabled")
}
}
/**
* Connect wallet button pressed.
*/
async function onConnect() {
console.log("Opening a dialog", web3Modal);
try {
provider = await web3Modal.connect();
} catch(e) {
console.log("Could not get a wallet connection", e);
return;
}
// Subscribe to accounts change
provider.on("accountsChanged", (accounts) => {
fetchAccountData();
});
// Subscribe to chainId change
provider.on("chainChanged", (chainId) => {
fetchAccountData();
});
// Subscribe to networkId change
provider.on("networkChanged", (networkId) => {
fetchAccountData();
});
await refreshAccountData();
}
/**
* Disconnect wallet button pressed.
*/
async function onDisconnect() {
console.log("Killing the wallet connection", provider);
// TODO: Which providers have close method?
if(provider.close) {
await provider.close();
// If the cached provider is not cleared,
// WalletConnect will default to the existing session
// and does not allow to re-scan the QR code with a new wallet.
// Depending on your use case you may want or want not his behavir.
await web3Modal.clearCachedProvider();
provider = null;
}
selectedAccount = null;
// Set the UI back to the initial state
if(document.querySelector("#prepare")){document.querySelector("#prepare").style.display = "block";
document.querySelector("#connected").style.display = "none";
}
}
//custom functions
const contract_address = "XXXX";
const ABI = [XXXX]
var contractInterface = new web3.eth.Contract(ABI, contract_address)
export const eatBeans = async () => {
let address = selectedAccount
if (address) {
await contractInterface.methods.eatBeans().send({ from: address })
await fetchAccountData()
}
}
export default function Navbar() {
const color = useColorModeValue("dark", "light");
const bg = useColorModeValue("white", "gray.800");
const mobileNav = useDisclosure();
const size = "96px";
const { toggleColorMode: toggleMode } = useColorMode();
const text = useColorModeValue("dark", "light");
const SwitchIcon = useColorModeValue(FaMoon, FaSun);
// Button bgColor
const bgColor = useColorModeValue("blue.200", "blue.500");
return (
<Box shadow="2xl" borderRadius="3xl">
<div id="prepare">
<Button className="btn btn-primary" id="btn-connect" onClick={(e)=> {onConnect()}}>
Connect wallet
</Button>
</div>
<div id="connected" style={{display: 'none' }}>
<Button className="btn btn-primary" id="btn-connect" onClick={(e)=> {onDisconnect()}}>
Disconnect wallet
</Button>
</div>
<div id="network" style={{display: 'none' }}>
<p>
<strong>Selected account:</strong> <span id="selected-account"></span>
</p>
</div>
</Box>
);
}