Skip to content

Commit

Permalink
Enhance wallet connection flow and error handling in WalletModal and …
Browse files Browse the repository at this point in the history
…transaction messages
  • Loading branch information
arentant committed Dec 13, 2024
1 parent 0e7e98f commit 86af0dc
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 48 deletions.
42 changes: 28 additions & 14 deletions components/Input/SourceWalletPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SwapFormValues } from "../DTOs/SwapFormValues";
import { Dispatch, FC, SetStateAction, useEffect, useState } from "react";
import useWallet from "../../hooks/useWallet";
import shortenAddress from "../utils/ShortenAddress";
import { ChevronDown } from "lucide-react";
import { ChevronDown, CircleHelp } from "lucide-react";
import Balance from "./dynamic/Balance";
import { useSwapDataState, useSwapDataUpdate } from "../../context/swap";
import VaulDrawer, { WalletFooterPortal } from "../modal/vaulModal";
Expand All @@ -12,6 +12,7 @@ import WalletIcon from "../icons/WalletIcon";
import SubmitButton from "../buttons/submitButton";
import { useConnectModal } from "../WalletModal";
import WalletsList from "../Wallet/WalletsList";
import { Tooltip, TooltipContent, TooltipTrigger } from "../shadcn/tooltip";

const Component: FC = () => {
const [openModal, setOpenModal] = useState<boolean>(false)
Expand Down Expand Up @@ -79,7 +80,7 @@ const Component: FC = () => {
<div className="flex items-center space-x-2 text-sm leading-4">
<div onClick={handleWalletChange} className="rounded-md bg-secondary-500 flex space-x-1 items-center py-0.5 pl-2 pr-1 cursor-pointer">
<div className="text-secondary-text">
Deposit address
Manual Transfer
</div>
<div className="w-5 h-5 items-center flex">
<ChevronDown className="h-4 w-4" aria-hidden="true" />
Expand Down Expand Up @@ -123,9 +124,7 @@ const Component: FC = () => {
/>
{
values.from?.deposit_methods.includes('deposit_address') &&
<div onClick={() => handleSelectWallet()} className="underline text-base text-center text-secondary-text cursor-pointer">
Continue without a wallet
</div>
<ContinueWithoutWallet onClick={handleSelectWallet} />
}
</VaulDrawer.Snap >
</VaulDrawer>
Expand Down Expand Up @@ -184,9 +183,8 @@ export const FormSourceWalletButton: FC = () => {
{
mountWalletPortal && values.from?.deposit_methods.includes('deposit_address') && values.depositMethod !== 'deposit_address' &&
<WalletFooterPortal isWalletModalOpen={isWalletModalOpen}>
<div onClick={() => handleSelectWallet()} className="underline text-base text-center text-secondary-text cursor-pointer pt-3">
Continue without a wallet
</div>
<ContinueWithoutWallet onClick={handleSelectWallet} />

</WalletFooterPortal>
}
</>
Expand Down Expand Up @@ -217,9 +215,7 @@ export const FormSourceWalletButton: FC = () => {
{
mountWalletPortal && values.from?.deposit_methods.includes('deposit_address') && values.depositMethod !== 'deposit_address' &&
<WalletFooterPortal isWalletModalOpen={isWalletModalOpen}>
<div onClick={() => handleSelectWallet()} className="underline text-base text-center text-secondary-text cursor-pointer pt-3">
Continue without a wallet
</div>
<ContinueWithoutWallet onClick={handleSelectWallet} />
</WalletFooterPortal>
}
</>
Expand All @@ -229,9 +225,7 @@ export const FormSourceWalletButton: FC = () => {
{
mountWalletPortal &&
<WalletFooterPortal isWalletModalOpen={isWalletModalOpen}>
<div onClick={() => handleSelectWallet()} className="underline text-base text-center text-secondary-text cursor-pointer pt-3">
Continue without a wallet
</div>
<ContinueWithoutWallet onClick={handleSelectWallet} />
</WalletFooterPortal>
}
</>
Expand All @@ -251,4 +245,24 @@ const Connect: FC<{ connectFn?: () => Promise<Wallet | undefined | void>; setMou
</SubmitButton>
}

const ContinueWithoutWallet: FC<{ onClick: () => void }> = ({ onClick }) => {
return (
<div className="inline-flex items-center gap-1.5 justify-center w-full pt-3">
<button onClick={onClick} className="underline hover:no-underline text-base text-center text-secondary-text cursor-pointer ">
Continue without a wallet
</button>
<Tooltip delayDuration={100}>
<TooltipTrigger>
<div className="text-xs text-secondary-text hover:text-primary-text rounded-full transition-colors duration-200 ">
<CircleHelp className="h-5 w-5" />
</div>
</TooltipTrigger>
<TooltipContent className="max-w-[300px]">
<p>Get a deposit address, send your crypto from any external wallet or exchange, and we'll handle the rest.</p>
</TooltipContent>
</Tooltip>
</div>
)
}

export default Component
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import resolveError from "./resolveError"
import { ActionData } from "./sharedTypes"
import { BaseError } from 'viem'
import { datadogRum } from '@datadog/browser-rum';
import { addressFormat } from "../../../../../lib/address/formatter"
import shortenAddress from "../../../../utils/ShortenAddress"

type TransactionMessageProps = {
wait?: ActionData,
Expand Down Expand Up @@ -33,7 +33,7 @@ const TransactionMessage: FC<TransactionMessageProps> = ({
return <TransactionRejectedMessage />
}
else if (transaction.isError && activeAddress && selectedSourceAddress && (activeAddress?.toLowerCase() !== selectedSourceAddress?.toLowerCase())) {
return <UnknowndMessage />
return <WaletMismatchMessage address={selectedSourceAddress} />
}
else if (hasError) {
const unexpectedError = transaction?.error?.['data']?.message || transaction?.error
Expand Down Expand Up @@ -84,11 +84,11 @@ const TransactionRejectedMessage: FC = () => {
details={`You've rejected the transaction in your wallet. Click “Try again” to open the prompt again.`} />
}

const UnknowndMessage: FC = () => {
const WaletMismatchMessage: FC<{ address: string }> = ({ address }) => {
return <WalletMessage
status="error"
header='Unknown Message'
details={`Lorem ipsum`} />
header='Wallet mismatch'
details={`Select ${shortenAddress(address)} in MetaMask, then try again`} />
}

const UexpectedErrorMessage: FC<{ message: string }> = ({ message }) => {
Expand Down
7 changes: 4 additions & 3 deletions components/WalletModal/ProvidersList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import { FC } from "react";
import useWallet from "../../hooks/useWallet";
import { ResolveConnectorIcon } from "../icons/ConnectorIcons";
import { useConnectModal } from ".";
import { WalletProvider } from "../../Models/WalletProvider";
import { Wallet, WalletProvider } from "../../Models/WalletProvider";

const ProvidersList: FC = () => {
const ProvidersList: FC<{ onFinish: (result: Wallet) => void }> = ({ onFinish }) => {
const { providers } = useWallet();
const filteredProviders = providers.filter(p => !!p.autofillSupportedNetworks)
const { setSelectedProvider } = useConnectModal()

const connect = async (provider: WalletProvider) => {
if (!provider.availableWalletsForConnect) {
await provider.connectWallet()
const result = await provider.connectWallet()
if (result) onFinish(result)
} else {
setSelectedProvider(provider)
}
Expand Down
4 changes: 3 additions & 1 deletion components/WalletModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ export function WalletModalProvider({ children }) {
selectedProvider={selectedProvider}
/>
:
<ProvidersList />
<ProvidersList
onFinish={onFinish}
/>
}
</VaulDrawer.Snap>
</VaulDrawer>
Expand Down
62 changes: 44 additions & 18 deletions lib/wallets/evm/useEVM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,6 @@ export default function useEVM({ network }: Props): WalletProvider {
const connections = getConnections(config)
return activeConnectors.map((w): Wallet | undefined => {

//TODO: handle Ronin wallet case
// let roninWalletNetworks = [
// KnownInternalNames.Networks.RoninMainnet,
// KnownInternalNames.Networks.EthereumMainnet,
// KnownInternalNames.Networks.PolygonMainnet,
// KnownInternalNames.Networks.BNBChainMainnet,
// KnownInternalNames.Networks.ArbitrumMainnet];

// if (connector == "com.roninchain.wallet" && network && !roninWalletNetworks.includes(network.name)) {
// return undefined;
// }

const connection = connections.find(c => c.connector.id === w.id)

const wallet = ResolveWallet({
Expand Down Expand Up @@ -236,7 +224,7 @@ const getWalletConnectUri = async (
const isNotAvailable = (connector: Connector | undefined, network: Network | undefined) => {
if (!network) return false
if (!connector) return true
return connector.id === "com.immutable.passport" && !network.name.toLowerCase().startsWith("immutable")
return resolveSupportedNetworks([network.name], connector.id).length === 0
}

type ResolveWalletProps = {
Expand All @@ -259,6 +247,7 @@ type ResolveWalletProps = {
},
providerName: string
}

const ResolveWallet = (props: ResolveWalletProps): Wallet | undefined => {
const { activeConnection, connection, networks, discconnect, network, supportedNetworks, providerName } = props
const accountIsActive = activeConnection?.id === connection?.connector.id
Expand All @@ -273,7 +262,8 @@ const ResolveWallet = (props: ResolveWalletProps): Wallet | undefined => {
if (!address) return undefined

const walletname = `${connector?.name} - ${connector.id === "com.immutable.passport" ? "Immutable" : "EVM"}`
return {

const wallet = {
id: connector.name,
isActive: accountIsActive,
address,
Expand All @@ -283,10 +273,46 @@ const ResolveWallet = (props: ResolveWalletProps): Wallet | undefined => {
icon: resolveWalletConnectorIcon({ connector: evmConnectorNameResolver(connector), address, iconUrl: connector.icon }),
disconnect: () => discconnect(connector.name),
isNotAvailable: isNotAvailable(connector, network),
//TODO:refactor this
asSourceSupportedNetworks: connector.id === "com.immutable.passport" ? supportedNetworks.asSource.filter(n => n.toLowerCase().startsWith("immutable")) : supportedNetworks.asSource,
autofillSupportedNetworks: connector.id === "com.immutable.passport" ? supportedNetworks.autofill.filter(n => n.toLowerCase().startsWith("immutable")) : supportedNetworks.autofill,
withdrawalSupportedNetworks: connector.id === "com.immutable.passport" ? supportedNetworks.withdrawal.filter(n => n.toLowerCase().startsWith("immutable")) : supportedNetworks.withdrawal,
asSourceSupportedNetworks: resolveSupportedNetworks(supportedNetworks.asSource, connector.id),
autofillSupportedNetworks: resolveSupportedNetworks(supportedNetworks.autofill, connector.id),
withdrawalSupportedNetworks: resolveSupportedNetworks(supportedNetworks.withdrawal, connector.id),
networkIcon: networks.find(n => connector?.id === "com.immutable.passport" ? immutableZKEvm.some(name => name === n.name) : ethereumNames.some(name => name === n.name))?.logo
}

return wallet
}

const resolveSupportedNetworks = (supportedNetworks: string[], connectorId: string) => {

const specificNetworksConnectors = [
{
id: "com.immutable.passport",
supportedNetworks: [
KnownInternalNames.Networks.ImmutableXMainnet,
KnownInternalNames.Networks.ImmutableXGoerli,
KnownInternalNames.Networks.ImmutableXSepolia,
KnownInternalNames.Networks.ImmutableZkEVM
]
},
{
id: "com.roninchain.wallet",
supportedNetworks: [
KnownInternalNames.Networks.RoninMainnet,
KnownInternalNames.Networks.EthereumMainnet,
KnownInternalNames.Networks.PolygonMainnet,
KnownInternalNames.Networks.BNBChainMainnet,
KnownInternalNames.Networks.ArbitrumMainnet
]
}
]

const specificNetworks = specificNetworksConnectors.find(c => c.id === connectorId)

if (specificNetworks) {
const values = specificNetworks.supportedNetworks.filter(n => supportedNetworks.some(name => name === n))
return values
}

return supportedNetworks

}
13 changes: 6 additions & 7 deletions lib/wallets/ton/useTON.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { ConnectedWallet, useTonConnectUI, useTonWallet, WalletInfo } from "@tonconnect/ui-react"
import { ConnectedWallet, useTonConnectUI, useTonWallet } from "@tonconnect/ui-react"
import { Address } from "@ton/core";
import KnownInternalNames from "../../knownIds";
import { Wallet, WalletProvider } from "../../../Models/WalletProvider";
import { resolveWalletConnectorIcon } from "../utils/resolveWalletIcon";
import { useSettingsState } from "../../../context/settings";


const tonNames = [KnownInternalNames.Networks.TONMainnet, KnownInternalNames.Networks.TONTestnet]
export default function useTON(): WalletProvider {
const { networks } = useSettingsState()

Expand Down Expand Up @@ -37,7 +35,7 @@ export default function useTON(): WalletProvider {
withdrawalSupportedNetworks: commonSupportedNetworks,
autofillSupportedNetworks: commonSupportedNetworks,
asSourceSupportedNetworks: commonSupportedNetworks,
networkIcon: networks.find(n => tonNames.some(name => name === n.name))?.logo
networkIcon: networks.find(n => commonSupportedNetworks.some(name => name === n.name))?.logo
} : undefined

const getWallet = () => {
Expand All @@ -54,14 +52,15 @@ export default function useTON(): WalletProvider {
await disconnectWallets()
}

function connectAndWaitForStatusChange(wallet) {
function connectAndWaitForStatusChange() {
return new Promise((resolve, reject) => {
try {
// Initiate the connection
tonConnectUI.openModal();

// Listen for the status change
tonConnectUI.onStatusChange((status) => {
debugger
if (status) resolve(status); // Resolve the promise with the status
});
} catch (error) {
Expand All @@ -71,7 +70,7 @@ export default function useTON(): WalletProvider {
});
}

const result: Wallet | undefined = await connectAndWaitForStatusChange(tonWallet)
const result: Wallet | undefined = await connectAndWaitForStatusChange()
.then((status: ConnectedWallet) => {
const connectedAddress = Address.parse(status.account.address).toString({ bounceable: false })
const connectedName = status.device.appName
Expand All @@ -88,7 +87,7 @@ export default function useTON(): WalletProvider {
withdrawalSupportedNetworks: commonSupportedNetworks,
autofillSupportedNetworks: commonSupportedNetworks,
asSourceSupportedNetworks: commonSupportedNetworks,
networkIcon: networks.find(n => tonNames.some(name => name === n.name))?.logo
networkIcon: networks.find(n => commonSupportedNetworks.some(name => name === n.name))?.logo
} : undefined

return wallet ? wallet : undefined
Expand Down

0 comments on commit 86af0dc

Please sign in to comment.