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 classNames from 'classnames'
import { useCallback, useEffect, useState } from 'react'
import useClipboard from 'react-use-clipboard'
import { useLocation, useNavigate } from 'react-router-dom'
import useClipboard from 'react-use-clipboard'
import Button from 'components/Button'
import { CircularProgress } from 'components/CircularProgress'
@ -60,7 +60,7 @@ export default function WalletConnectedButton() {
const onDisconnectWallet = () => {
if (!currentWallet) return
disconnectWallet(currentWallet)
useStore.setState({ client: undefined, balances: [] })
useStore.setState({ client: undefined, address: undefined, accounts: null, balances: [] })
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 Image from 'next/image'
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import QRCode from 'react-qr-code'
import Button from 'components/Button'
import { CircularProgress } from 'components/CircularProgress'
import FullOverlayContent from 'components/FullOverlayContent'
import { ChevronLeft, ChevronRight } from 'components/Icons'
import Text from 'components/Text'
import WalletFetchBalancesAndAccounts from 'components/Wallet/WalletFetchBalancesAndAccounts'
import WalletConnecting from 'components/Wallet/WalletConnecting'
import { CHAINS } from 'constants/chains'
import { ENV } from 'constants/env'
import { WALLETS } from 'constants/wallets'
import useToggle from 'hooks/useToggle'
import useStore from 'store'
import { WalletID } from 'types/enums/wallet'
import { isAndroid, isIOS, isMobile } from 'utils/mobile'
interface Props {
error?: ErrorObject
}
interface ErrorObject {
title: string
message: string
}
interface WalletOptionProps {
name: string
imageSrc: string
@ -27,16 +33,6 @@ interface WalletOptionProps {
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
}
function WalletOption(props: WalletOptionProps) {
return (
<Button
@ -57,44 +53,16 @@ function WalletOption(props: WalletOptionProps) {
)
}
export default function WalletSelect() {
const { extensionProviders, mobileProviders, connect, mobileConnect, simulate, sign, broadcast } =
useShuttle()
const [isConnecting, setIsConnecting] = useToggle(false)
export default function WalletSelect(props: Props) {
const { extensionProviders, mobileProviders, mobileConnect } = useShuttle()
const [qrCodeUrl, setQRCodeUrl] = useState('')
const [error, setError] = useState(props.error)
const sortedExtensionProviders = extensionProviders.sort((a, b) => +b - +a)
const handleConnectClick = async (extensionProviderId: string, chainId: string) => {
setIsConnecting(true)
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 handleConnectClick = (extensionProviderId: string) => {
useStore.setState({
focusComponent: <WalletConnecting providerId={extensionProviderId} />,
})
}
const handleMobileConnectClick = async (mobileProviderId: string, chainId: string) => {
@ -112,33 +80,27 @@ export default function WalletSelect() {
} else {
window.location.href = urls.androidUrl
}
setIsConnecting(true)
} else {
setQRCodeUrl(urls.qrCodeUrl)
setIsConnecting(false)
}
} catch (error) {
if (error instanceof Error) {
useStore.setState({
toast: {
isError: true,
title: 'Failed to connect to wallet',
message: error.message,
},
})
setError({ title: 'Failed to connect to wallet', message: error.message })
}
}
}
if (isConnecting)
return (
<FullOverlayContent
title={'Connecting...'}
copy={'Unlock your wallet and approve the connection'}
>
<CircularProgress size={40} />
</FullOverlayContent>
)
useEffect(() => {
if (error?.message && error?.title) {
useStore.setState({
toast: {
isError: true,
title: error.title,
message: error.message,
},
})
}
}, [error?.message, error?.title])
if (qrCodeUrl)
return (
@ -193,7 +155,7 @@ export default function WalletSelect() {
return (
<WalletOption
key={`${walletId}-${network.chainId}`}
handleClick={() => handleConnectClick(walletId, network.chainId)}
handleClick={() => handleConnectClick(walletId)}
imageSrc={WALLETS[walletId].imageURL}
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 { useLocation, useNavigate, useParams } from 'react-router-dom'
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
import WalletConnectedButton from 'components/Wallet/WalletConnectedButton'
import WalletConnecting from 'components/Wallet/WalletConnecting'
import useCurrentWallet from 'hooks/useCurrentWallet'
import useStore from 'store'
import { getPage, getRoute } from 'utils/route'
@ -14,39 +13,22 @@ export default function Wallet() {
const { address: addressInUrl } = useParams()
const { pathname } = useLocation()
const currentWallet = useCurrentWallet()
const { simulate, sign, broadcast } = useShuttle()
const address = useStore((s) => s.address)
const client = useStore((s) => s.client)
// Set connection status
useEffect(() => {
const isConnected = !!currentWallet
useStore.setState(
isConnected
? {
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 })
if (!currentWallet) {
useStore.setState({ address: undefined, accounts: null, client: undefined })
return
}
getCosmWasmClient()
}, [currentWallet, address, simulate, sign, broadcast, client])
if (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
useEffect(() => {