fix: fixed the wallet auto connection (#341)

* fix: fixed the wallet auto connection

* tidy: refactor

* fix: re-enabled account change support

* tidy: refactor
This commit is contained in:
Linkie Link 2023-08-05 11:11:07 +02:00 committed by GitHub
parent 267b968c4a
commit cec9e50955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 100 deletions

View File

@ -2,8 +2,8 @@ import { useShuttle } from '@delphi-labs/shuttle-react'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import classNames from 'classnames' import classNames from 'classnames'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import useClipboard from 'react-use-clipboard'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import useClipboard from 'react-use-clipboard'
import Button from 'components/Button' import Button from 'components/Button'
import { CircularProgress } from 'components/CircularProgress' import { CircularProgress } from 'components/CircularProgress'
@ -60,7 +60,7 @@ export default function WalletConnectedButton() {
const onDisconnectWallet = () => { const onDisconnectWallet = () => {
if (!currentWallet) return if (!currentWallet) return
disconnectWallet(currentWallet) disconnectWallet(currentWallet)
useStore.setState({ client: undefined, balances: [] }) useStore.setState({ client: undefined, address: undefined, accounts: null, balances: [] })
navigate(getRoute(getPage(pathname))) navigate(getRoute(getPage(pathname)))
} }

View File

@ -0,0 +1,94 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { useShuttle } from '@delphi-labs/shuttle-react'
import { useEffect } from 'react'
import { CircularProgress } from 'components/CircularProgress'
import FullOverlayContent from 'components/FullOverlayContent'
import WalletSelect from 'components/Wallet//WalletSelect'
import WalletFetchBalancesAndAccounts from 'components/Wallet/WalletFetchBalancesAndAccounts'
import { CHAINS } from 'constants/chains'
import { ENV } from 'constants/env'
import useToggle from 'hooks/useToggle'
import useStore from 'store'
interface Props {
autoConnect?: boolean
providerId?: string
}
const currentChainId = ENV.CHAIN_ID
const currentChain = CHAINS[currentChainId]
const mapErrorMessages = (providerId: string, errorMessage: string) => {
if (providerId === 'station') {
if (errorMessage.match('Wallet not connected to the network with chainId')) {
return `Your wallet is not connected to the correct network. Please switch your wallet to the ${currentChain.name} network`
}
}
return errorMessage
}
export default function WalletConnecting(props: Props) {
const { extensionProviders, recentWallet, connect, simulate, sign, broadcast } = useShuttle()
const [isConnecting, setIsConnecting] = useToggle()
const providerId = props.providerId ?? recentWallet?.providerId
const isAutoConnect = props.autoConnect
const handleConnect = async (extensionProviderId: string) => {
setIsConnecting(true)
try {
const provider = extensionProviders.find((p) => p.id === providerId)
const response =
isAutoConnect && provider
? await provider.connect({ chainId: currentChainId })
: await connect({ extensionProviderId, chainId: currentChainId })
const cosmClient = await CosmWasmClient.connect(response.network.rpc)
const walletClient: WalletClient = {
broadcast,
cosmWasmClient: cosmClient,
connectedWallet: response,
sign,
simulate,
}
setIsConnecting(false)
useStore.setState({
client: walletClient,
address: response.account.address,
focusComponent: <WalletFetchBalancesAndAccounts />,
})
} catch (error) {
if (error instanceof Error) {
setIsConnecting(false)
useStore.setState({
client: undefined,
address: undefined,
accounts: null,
focusComponent: (
<WalletSelect
error={{
title: 'Failed to connect to wallet',
message: mapErrorMessages(extensionProviderId, error.message),
}}
/>
),
})
}
}
}
useEffect(() => {
if (isConnecting || !providerId) return
handleConnect(providerId)
}, [isConnecting, providerId, handleConnect])
return (
<FullOverlayContent
title={'Connecting...'}
copy={'Unlock your wallet and approve the connection'}
>
<CircularProgress size={40} />
</FullOverlayContent>
)
}

View File

@ -1,23 +1,29 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { useShuttle } from '@delphi-labs/shuttle-react' import { useShuttle } from '@delphi-labs/shuttle-react'
import Image from 'next/image' import Image from 'next/image'
import React, { useState } from 'react' import React, { useEffect, useState } from 'react'
import QRCode from 'react-qr-code' import QRCode from 'react-qr-code'
import Button from 'components/Button' import Button from 'components/Button'
import { CircularProgress } from 'components/CircularProgress'
import FullOverlayContent from 'components/FullOverlayContent' import FullOverlayContent from 'components/FullOverlayContent'
import { ChevronLeft, ChevronRight } from 'components/Icons' import { ChevronLeft, ChevronRight } from 'components/Icons'
import Text from 'components/Text' import Text from 'components/Text'
import WalletFetchBalancesAndAccounts from 'components/Wallet/WalletFetchBalancesAndAccounts' import WalletConnecting from 'components/Wallet/WalletConnecting'
import { CHAINS } from 'constants/chains' import { CHAINS } from 'constants/chains'
import { ENV } from 'constants/env' import { ENV } from 'constants/env'
import { WALLETS } from 'constants/wallets' import { WALLETS } from 'constants/wallets'
import useToggle from 'hooks/useToggle'
import useStore from 'store' import useStore from 'store'
import { WalletID } from 'types/enums/wallet' import { WalletID } from 'types/enums/wallet'
import { isAndroid, isIOS, isMobile } from 'utils/mobile' import { isAndroid, isIOS, isMobile } from 'utils/mobile'
interface Props {
error?: ErrorObject
}
interface ErrorObject {
title: string
message: string
}
interface WalletOptionProps { interface WalletOptionProps {
name: string name: string
imageSrc: string imageSrc: string
@ -27,16 +33,6 @@ interface WalletOptionProps {
const currentChainId = ENV.CHAIN_ID const currentChainId = ENV.CHAIN_ID
const currentChain = CHAINS[currentChainId] const currentChain = CHAINS[currentChainId]
const mapErrorMessages = (providerId: string, errorMessage: string) => {
if (providerId === 'station') {
if (errorMessage.match('Wallet not connected to the network with chainId')) {
return `Your wallet is not connected to the correct network. Please switch your wallet to the ${currentChain.name} network`
}
}
return errorMessage
}
function WalletOption(props: WalletOptionProps) { function WalletOption(props: WalletOptionProps) {
return ( return (
<Button <Button
@ -57,44 +53,16 @@ function WalletOption(props: WalletOptionProps) {
) )
} }
export default function WalletSelect() { export default function WalletSelect(props: Props) {
const { extensionProviders, mobileProviders, connect, mobileConnect, simulate, sign, broadcast } = const { extensionProviders, mobileProviders, mobileConnect } = useShuttle()
useShuttle()
const [isConnecting, setIsConnecting] = useToggle(false)
const [qrCodeUrl, setQRCodeUrl] = useState('') const [qrCodeUrl, setQRCodeUrl] = useState('')
const [error, setError] = useState(props.error)
const sortedExtensionProviders = extensionProviders.sort((a, b) => +b - +a) const sortedExtensionProviders = extensionProviders.sort((a, b) => +b - +a)
const handleConnectClick = async (extensionProviderId: string, chainId: string) => { const handleConnectClick = (extensionProviderId: string) => {
setIsConnecting(true) useStore.setState({
focusComponent: <WalletConnecting providerId={extensionProviderId} />,
try { })
const response = await connect({ extensionProviderId, chainId })
const cosmClient = await CosmWasmClient.connect(response.network.rpc)
const walletClient: WalletClient = {
broadcast,
cosmWasmClient: cosmClient,
connectedWallet: response,
sign,
simulate,
}
useStore.setState({
client: walletClient,
address: response.account.address,
focusComponent: <WalletFetchBalancesAndAccounts />,
})
} catch (error) {
if (error instanceof Error) {
useStore.setState({
toast: {
isError: true,
title: 'Failed to connect to wallet',
message: mapErrorMessages(extensionProviderId, error.message),
},
})
}
}
setIsConnecting(false)
} }
const handleMobileConnectClick = async (mobileProviderId: string, chainId: string) => { const handleMobileConnectClick = async (mobileProviderId: string, chainId: string) => {
@ -112,33 +80,27 @@ export default function WalletSelect() {
} else { } else {
window.location.href = urls.androidUrl window.location.href = urls.androidUrl
} }
setIsConnecting(true)
} else { } else {
setQRCodeUrl(urls.qrCodeUrl) setQRCodeUrl(urls.qrCodeUrl)
setIsConnecting(false)
} }
} catch (error) { } catch (error) {
if (error instanceof Error) { if (error instanceof Error) {
useStore.setState({ setError({ title: 'Failed to connect to wallet', message: error.message })
toast: {
isError: true,
title: 'Failed to connect to wallet',
message: error.message,
},
})
} }
} }
} }
if (isConnecting) useEffect(() => {
return ( if (error?.message && error?.title) {
<FullOverlayContent useStore.setState({
title={'Connecting...'} toast: {
copy={'Unlock your wallet and approve the connection'} isError: true,
> title: error.title,
<CircularProgress size={40} /> message: error.message,
</FullOverlayContent> },
) })
}
}, [error?.message, error?.title])
if (qrCodeUrl) if (qrCodeUrl)
return ( return (
@ -193,7 +155,7 @@ export default function WalletSelect() {
return ( return (
<WalletOption <WalletOption
key={`${walletId}-${network.chainId}`} key={`${walletId}-${network.chainId}`}
handleClick={() => handleConnectClick(walletId, network.chainId)} handleClick={() => handleConnectClick(walletId)}
imageSrc={WALLETS[walletId].imageURL} imageSrc={WALLETS[walletId].imageURL}
name={WALLETS[walletId].name ?? 'Conenct Wallet'} name={WALLETS[walletId].name ?? 'Conenct Wallet'}
/> />

View File

@ -1,10 +1,9 @@
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
import { useShuttle } from '@delphi-labs/shuttle-react'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom' import { useLocation, useNavigate, useParams } from 'react-router-dom'
import WalletConnectButton from 'components/Wallet/WalletConnectButton' import WalletConnectButton from 'components/Wallet/WalletConnectButton'
import WalletConnectedButton from 'components/Wallet/WalletConnectedButton' import WalletConnectedButton from 'components/Wallet/WalletConnectedButton'
import WalletConnecting from 'components/Wallet/WalletConnecting'
import useCurrentWallet from 'hooks/useCurrentWallet' import useCurrentWallet from 'hooks/useCurrentWallet'
import useStore from 'store' import useStore from 'store'
import { getPage, getRoute } from 'utils/route' import { getPage, getRoute } from 'utils/route'
@ -14,39 +13,22 @@ export default function Wallet() {
const { address: addressInUrl } = useParams() const { address: addressInUrl } = useParams()
const { pathname } = useLocation() const { pathname } = useLocation()
const currentWallet = useCurrentWallet() const currentWallet = useCurrentWallet()
const { simulate, sign, broadcast } = useShuttle()
const address = useStore((s) => s.address) const address = useStore((s) => s.address)
const client = useStore((s) => s.client) const client = useStore((s) => s.client)
// Set connection status
useEffect(() => { useEffect(() => {
const isConnected = !!currentWallet if (!currentWallet) {
useStore.setState( useStore.setState({ address: undefined, accounts: null, client: undefined })
isConnected return
? {
address: currentWallet.account.address,
}
: { address: undefined, accounts: null, client: undefined },
)
}, [currentWallet])
// Set the client
useEffect(() => {
async function getCosmWasmClient() {
if (client || !currentWallet) return
const cosmClient = await CosmWasmClient.connect(currentWallet.network.rpc)
const walletClient: WalletClient = {
broadcast,
cosmWasmClient: cosmClient,
connectedWallet: currentWallet,
sign,
simulate,
}
useStore.setState({ client: walletClient })
} }
getCosmWasmClient() if (client) {
}, [currentWallet, address, simulate, sign, broadcast, client]) if (currentWallet.account.address !== address)
useStore.setState({ address: currentWallet.account.address })
return
}
useStore.setState({ focusComponent: <WalletConnecting autoConnect /> })
}, [currentWallet, client, address])
// Redirect when switching wallets or on first connection // Redirect when switching wallets or on first connection
useEffect(() => { useEffect(() => {