Open cryptod00c opened 2 years ago
i have same issue. how do you check the wallet is connected or not? @cryptod00c
@kai-zhong I'm managing that state locally...basically I set a property when the wallet is connected the first time and then check it on load...looks something like this...
useEffect(() => {
if (
!isDisconnected?.includes(WalletEnum.metamask) &&
previousConnections.includes(WalletEnum.metamask)
) {
void metaMask.connectEagerly();
}
}, []);
the state is persisted in localStorage?
I have my state persisted in zustand @kai-zhong
import { persist, PersistOptions } from 'zustand/middleware';
@cryptod00c ok, thanks.
i take a look at implementation of MetaMask connector.
public async connectEagerly(): Promise<void> {
const cancelActivation = this.actions.startActivation()
await this.isomorphicInitialize()
if (!this.provider) return cancelActivation()
return Promise.all([
this.provider.request({ method: 'eth_chainId' }) as Promise<string>,
this.provider.request({ method: 'eth_accounts' }) as Promise<string[]>,
])
.then(([chainId, accounts]) => {
if (accounts.length) {
this.actions.update({ chainId: parseChainId(chainId), accounts })
} else {
throw new Error('No accounts returned')
}
})
.catch((error) => {
console.debug('Could not connect eagerly', error)
cancelActivation()
})
}
and cancelActivation() implementation
/**
* Sets activating to true, indicating that an update is in progress.
*
* @returns cancelActivation - A function that cancels the activation by setting activating to false,
* as long as there haven't been any intervening updates.
*/
function startActivation(): () => void {
const nullifierCached = ++nullifier
store.setState({ ...DEFAULT_STATE, activating: true })
// return a function that cancels the activation iff nothing else has happened
return () => {
if (nullifier === nullifierCached) store.setState({ activating: false })
}
}
stuck at if (nullifier === nullifierCached) store.setState({ activating: false })
. activating state is not set to false
properly, and no error is reported.
that should be super helpful to @NoahZinsmeister hopefully - nice research
@cryptod00c can you share your implementation you mentioned earlier?
Awesome library and fantastic examples - thanks for open sourcing this. I have a pretty straightforward multi chain wallet connection nav bar if you're at all interested in adding that to the example section...it's open-sourced as well.
I have the same issue. Thank you for reporting this.
But I have a question. Why doesn't this happen in the demo site (https://web3-react-mu.vercel.app//)? I try reproducing the same way as what happened locally but the connecting status seems to be correct and the user can connect manually after.
Hi, everyone. i have a workaround, i set a timeout in activating stage. In dev mode, activating stage is not stuck, the problem just present in production mode, and i don't know why.
however, example below can resolve my problem, hope to help you.
enum WalletState {
None,
Activating,
Active,
Inactive,
HasError,
ActivatingTimeout
}
function ContainerNode {
let router = useRouter()
let web3Hook = useWeb3React()
let [activatingTimeout, setActivatingTimeout] = useState<any>()
let [walletState, setWalletState] = useState(WalletState.None)
let [auth, setAuth] = useState(false)
let clearTimer = () => {
console.log('clear timers.')
activatingTimeout && clearTimeout(activatingTimeout)
}
let {asPath} = router
let {error, isActivating, isActive} = web3Hook
useEffect(() => {
console.log(asPath, WalletState[walletState], isActivating, isActive, error)
if (error) {
console.log('wallet error.', error)
setWalletState(WalletState.HasError)
return;
}
switch (walletState) {
case WalletState.None:
if (!isActivating) {
console.log('wallet connect eagerly.')
web3Hook.connector.connectEagerly?.()
setActivatingTimeout(setTimeout(() => {
setWalletState( s => {
console.log('wallet check activating timeout.', WalletState[s], s === WalletState.Activating)
if(s == WalletState.Activating) {
return WalletState.ActivatingTimeout
}
return s
})
}, 1000 * 5))
setWalletState(WalletState.Activating)
}
break
case WalletState.Activating:
if (isActivating) {
return
}
if (isActive) {
setWalletState(WalletState.Active)
} else {
setWalletState(WalletState.Inactive)
}
break
case WalletState.Active:
if (!isActive) {
setWalletState(WalletState.Inactive)
return
}
clearTimer()
// authenticate()
break
case WalletState.Inactive:
case WalletState.ActivatingTimeout:
default:
clearTimer()
router.replace({pathname: '/login', query: {from: router.asPath}}).finally()
}
return () => {
clearTimer()
}
}, [asPath, walletState, error, isActivating, isActive])
return <></>
}
https://github.com/NoahZinsmeister/web3-react/blob/main/packages/example-next/components/connectorCards/MetaMaskCard.tsx
it looks to be only an issue with MetaMask - where if the user has never connected with MetaMask previously, it attempts to eager connect and fails to resolve off of the "connecting" status - which subsequently (properly, I might add) - doesn't allow the user to manually connect, leaving them stuck. So right now I'm just manually handling whether they have connected previously before I trigger the
connectEagerly()
Awesome library and fantastic examples - thanks for open sourcing this. I have a pretty straightforward multi chain wallet connection nav bar if you're at all interested in adding that to the example section...it's open-sourced as well.