Closed dev-johnny-gh closed 1 year ago
Hi @duxiaofeng-github,
if you localStorage.getItem("WEB3_CONNECT_CACHED_PROVIDER")
you get if a provider was cached and the name of it.
Be sure to await this.web3Modal.clearCachedProvider();
on disconnect because "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".
(I'm not part of the team).
Thanks, Fredo
@4skinSkywalker thanks for the reply, according to your description, i will receive a cached provider, but i can't find out if it is connected or not unless i call the connect
method to force user to connect to their wallet. that's not what i want.
So if I understood you want the provider without the modal showing up, right?
(async function() {
// Get the cached provider from LocalStorage
const cachedProviderName = JSON.parse(localStorage.getItem("WEB3_CONNECT_CACHED_PROVIDER"));
// Get the connector for the cachedProviderName
const connector = web3Modal.providerController.providerOptions[cachedProviderName].connector;
// Evaluate connector() which returns a Proxy in the case of MetaMask
const proxy = await connector(); // Some connector may need providerPackage and opts
console.log("Proxy", proxy);
// Get the working provider from your favorite library (ethers, web3, ...)
const provider = new ethers.providers.Web3Provider(proxy); // If you use web3, then const web3 = new Web3(proxy);
console.log("Provider", provider);
// You can list the connected accounts without launching Web3Modal
console.log("Accounts", await provider.listAccounts()); // If you use web3, then await web3.eth.getAccounts();
})();
With the above code you should be able to leverage your Web3Modal configurations and get a working provider and feed it in your library of choice without the need of calling the connect method.
I've tested the above code and had the expected result:
Ah, you may need to put some if-clauses to guard from undefined, infact if there's no cached provider you get the following error:
Keep in mind I'm not part of the team, I'm not even an expert of this library. I just read their source code and come up with the above snippet.
Let's ask the guys from the project itself if my snippet is reliable: @miohtama, @jamesmorgan, @miguelmota, @ptescher and @arronhunt.
Anything on this?
@duxiaofeng-github , have you solved the problem ? I am stuck on it too.
How can I get the web3modal connected provider , after reload
@vanvantsyan you can only get provider by web3Modal.connect(). When you calling this method, the modal will popup up and i don't expect that. that's my question and it seems there is no solution right now.
@4skinSkywalker 's code may solve this problem, but it's a bit tricky. it interacts with ethers directly and uses some internal methods. that seems dirty and can be easily broken.
First thing: @vanvantsyan thank you for the downvote.
You can get providers the same way Web3Modal gets them (see web3modal connectors). I do this all the time. Web3Modal just abstracts away all the low-level logic to extract providers from the various sources (most of them are different properties in the window object) It's no voodoo magic.
Unless you take the provider you don't have a meaningful way to see if that provider was injected and unless you istantiate it via ethers or web3 you don't have a meaningful way to know what account is connected and on what network. If you don't want to spawn the dialog with .connect() then simply try to get the provider you want and check it's state by yourself.
Following some example on how you can get can providers:
if (typeof win.ethereum !== 'undefined') {
let provider = win.ethereum;
provider = await provider.request({ method: 'eth_requestAccounts' });
}
(This may also trigger other injected providers (e.g. Coinbase) but you can filter MetaMask if you want).
if (typeof win.BinanceChain!== 'undefined') {
let provider = win.BinanceChain;
provider = await provider.request({ method: 'eth_requestAccounts' });
}
let walletLink = new WalletLink({ appName });
let provider = walletLink.makeWeb3Provider(networkUrl, chainId);
let provider = await provider.enable();
let fm = new this.Fortmatic(FORTMATIC_APIKEY, { rpcUrl, chainId });
let provider = provider: fm.getProvider();
What I've just shown you is obviously painful and it's just to show you how you can do it manually! To do it without spawning the modal you'll have to import connectors from Web3Modal library and evaluate them. (see web3modal connectors).
@4skinSkywalker yep, that's the right way to achieve this goal. but i think it sholud be done by web3modal itself. it should make it easier to let people use web3 and its various providers, not more complex.
@4skinSkywalker , thanks for the valuable response. It helped. I have a not working case after implementing it. Is it possible to trigger chain change(with request method"wallet_switchEthereumChain") /chain adding ("wallet_addEthereumChain") on the mobile extension after being connected via web3modal (metamask app) and passing the returned provider to ethers.web3provider.
The methods triggering dialog only for MetaMask chrome extension, but when connected through the mobile app, they don't work. But at the same time f.e. "personal_sign" method works well and triggers dialog on the mobile.
Will be thankful for your help, can't find any info on this anywhere.
@4skinSkywalker , thanks for the valuable response. It helped. I have a not working case after implementing it. Is it possible to trigger chain change(with request method"wallet_switchEthereumChain") /chain adding ("wallet_addEthereumChain") on the mobile extension after being connected via web3modal (metamask app) and passing the returned provider to ethers.web3provider.
The methods triggering dialog only for MetaMask chrome extension, but when connected through the mobile app, they don't work. But at the same time f.e. "personal_sign" method works well and triggers dialog on the mobile.
Will be thankful for your help, can't find any info on this anywhere.
Did you figure this out? I needed help here as well.
I noticed there wasn't anything on this thread for a while, so perhaps there is a proper recommended solution, but in case not, here is my solution:
// If this is a tranparent (no pop-up desired) call and we don't have a
// cached provider return because it will trigger a pop-up
if (transparent && !web3Modal.cachedProvider) {
return
}
// If this isn't a transparent call, let's clear the cached provider
// to force the pop-up
if (!transparent) {
web3Modal.clearCachedProvider()
}
I have a connect function with a transparent bool. On first page load this is set to true, when triggered by a button click it's false.
If it's transparent (first load) I check for a cached provider, if I don't have one, I just exit and don't perform the connect.
Once you've done this, you're free to connect and it won't trigger the modal.
If it's not a transparent call (e.g. button click) I always clear the cached provider.
Hope this helps someone, seems to work but I need to test with a few more wallets.
Get MetaMask provider
if (typeof win.ethereum !== 'undefined') { let provider = win.ethereum; provider = await provider.request({ method: 'eth_requestAccounts' }); }
The above snippet will fire as long as a wallet extension is active. Meaning, even if a wallet is not connected to a website this will still return true and still run. Just needs to be updated to:
if (window?.ethereum?.selectedAddress) {
onConnect();
}
This way, it will only silently fire when there an address that we can retrieve (meaning the wallet had been connected before). For users that have never connected, they are not prompted with the pop-up and people that have been connected before are already connected.
For reference, this is all that takes place in my onConnect()
:
const onConnect = async () => {
try {
instance = await web3Modal.connect();
} catch(e) {
console.error(e)
}
instance.on('accountsChanged', fetchAccountData);
instance.on('chainChanged', fetchAccountData);
instance.on('networkChanged', fetchAccountData);
await refreshAccountData();
}
The far simplest solution out there and will give you the result that you are actually looking for 🤝 This does however primarily only work with injected wallets, and even then, the selectedAddress is not "always" available so if anyone has a simple fix to that, would be much appreciated.
With stable version 2.0.0 of Web3Modal now released, we are officially dropping support for version 1.x Due to this this issue/pr was marked for closing. It is highly recommended to upgrade as 2.x will be receiving further updates that will enable functionality for some of our newer sdks like auth and push as well as support for WalletConnect v2 (See this post about WalletConnect v1 being deprecated https://medium.com/walletconnect/walletconnect-v1-0-sunset-notice-and-migration-schedule-8af9d3720d2e)
If you need to continue using Web3Modal 1.x and require this feature/fix implemented, we suggest adding it via forking V1 branch.
i need to get a cached provider used by our user previously. if that provider is connected, i will get first user account and display it on the page. or if not, i don't want to invoke connect process by default, unless user click on the connect button.
some methods of web3js can detect whether a wallet connected to network or not. but i need to use
web3modal.connect()
to get a provider to construct a web3 instance.some code snippet:
so, is there any way to get a cached provider without calling the
connect
function? or any way to detect a cached provider is connected to network or not?