UNPKG

@lifi/wallet-management

Version:

LI.FI Wallet Management solution.

234 lines (205 loc) 7.82 kB
import { useConfig as useBigmiConfig } from '@bigmi/react' import { ChainType } from '@lifi/sdk' import type { Theme } from '@mui/material' import { useMediaQuery } from '@mui/material' import { WalletReadyState } from '@solana/wallet-adapter-base' import type { Wallet } from '@solana/wallet-adapter-react' import { useWallet } from '@solana/wallet-adapter-react' import { useMemo } from 'react' import type { Connector } from 'wagmi' import { useAccount, useConnect } from 'wagmi' import { defaultCoinbaseConfig } from '../config/coinbase.js' import { defaultMetaMaskConfig } from '../config/metaMask.js' import { defaultWalletConnectConfig } from '../config/walletConnect.js' import { createCoinbaseConnector } from '../connectors/coinbase.js' import { createMetaMaskConnector } from '../connectors/metaMask.js' import type { CreateConnectorFnExtended } from '../connectors/types.js' import { createWalletConnectConnector } from '../connectors/walletConnect.js' import { useWalletManagementConfig } from '../providers/WalletManagementProvider/WalletManagementContext.js' import type { WalletConnector } from '../types/walletConnector.js' import { getConnectorIcon } from '../utils/getConnectorIcon.js' import { getWalletPriority } from '../utils/getWalletPriority.js' import { isWalletInstalled } from '../utils/isWalletInstalled.js' export type CombinedWalletConnector = { connector: WalletConnector chainType: ChainType } export type CombinedWallet = { id: string name: string icon?: string connectors: CombinedWalletConnector[] } const normalizeName = (name: string) => name.split(' ')[0].toLowerCase().trim() const combineWalletLists = ( utxoConnectorList: (CreateConnectorFnExtended | Connector)[], evmConnectorList: (CreateConnectorFnExtended | Connector)[], svmWalletList: Wallet[] ): CombinedWallet[] => { const walletMap = new Map<string, CombinedWallet>() utxoConnectorList.forEach((utxo) => { const utxoName = (utxo as CreateConnectorFnExtended)?.displayName || (utxo as Connector)?.name const normalizedName = normalizeName(utxoName) const existing = walletMap.get(normalizedName) || { id: utxo.id, name: utxoName, icon: getConnectorIcon(utxo as Connector), connectors: [], } existing.connectors.push({ connector: utxo, chainType: ChainType.UTXO }) walletMap.set(normalizedName, existing) }) evmConnectorList.forEach((evm) => { const evmName = (evm as CreateConnectorFnExtended)?.displayName || (evm as Connector)?.name const normalizedName = normalizeName(evmName) const existing = walletMap.get(normalizedName) || { id: evm.id, name: evmName, icon: getConnectorIcon(evm as Connector), connectors: [], } existing.connectors.push({ connector: evm, chainType: ChainType.EVM }) walletMap.set(normalizedName, existing) }) svmWalletList.forEach((svm) => { const normalizedName = normalizeName(svm.adapter.name) const existing = walletMap.get(normalizedName) || { id: svm.adapter.name, name: svm.adapter.name, icon: svm.adapter.icon, connectors: [], } existing.connectors.push({ connector: svm.adapter, chainType: ChainType.SVM, }) walletMap.set(normalizedName, existing) }) const combinedWallets = Array.from(walletMap.values()) combinedWallets.sort(walletComparator) return combinedWallets } export const useCombinedWallets = () => { const walletConfig = useWalletManagementConfig() const bigmiConfig = useBigmiConfig() const wagmiAccount = useAccount() const bigmiAccount = useAccount({ config: bigmiConfig }) const { connectors: wagmiConnectors } = useConnect() const { connectors: bigmiConnectors } = useConnect({ config: bigmiConfig }) const { wallets: solanaWallets } = useWallet() const isDesktopView = useMediaQuery((theme: Theme) => theme.breakpoints.up('sm') ) const data = useMemo(() => { const evmConnectors: (CreateConnectorFnExtended | Connector)[] = Array.from(wagmiConnectors) // Ensure standard connectors are included if ( !evmConnectors.some((connector) => connector.id.toLowerCase().includes('walletconnect') ) ) { evmConnectors.unshift( createWalletConnectConnector( walletConfig?.walletConnect ?? defaultWalletConnectConfig ) ) } if ( !evmConnectors.some((connector) => connector.id.toLowerCase().includes('coinbase') ) ) { evmConnectors.unshift( createCoinbaseConnector(walletConfig?.coinbase ?? defaultCoinbaseConfig) ) } if ( !evmConnectors.some((connector) => connector.id.toLowerCase().includes('metamask') ) ) { evmConnectors.unshift( createMetaMaskConnector(walletConfig?.metaMask ?? defaultMetaMaskConfig) ) } const includeEcosystem = (chainType: ChainType) => !walletConfig.enabledChainTypes || walletConfig.enabledChainTypes.includes(chainType) const installedUTXOConnectors = includeEcosystem(ChainType.UTXO) ? bigmiConnectors.filter((connector) => { const isInstalled = isWalletInstalled(connector.id) const isConnected = bigmiAccount.connector?.id === connector.id return isInstalled && !isConnected }) : [] const installedEVMConnectors = includeEcosystem(ChainType.EVM) ? evmConnectors.filter((connector) => { const isInstalled = isWalletInstalled(connector.id) const isConnected = wagmiAccount.connector?.id === connector.id return isInstalled && !isConnected }) : [] const installedSVMWallets = includeEcosystem(ChainType.SVM) ? solanaWallets.filter((wallet) => { const isInstalled = wallet.adapter.readyState === WalletReadyState.Installed || wallet.adapter.readyState === WalletReadyState.Loadable const isConnected = wallet.adapter.connected return isInstalled && !isConnected }) : [] const installedCombinedWallets = combineWalletLists( installedUTXOConnectors, installedEVMConnectors, installedSVMWallets ) const notDetectedUTXOConnectors = bigmiConnectors.filter((connector) => { const isInstalled = isWalletInstalled(connector.id) return !isInstalled && isDesktopView }) const notDetectedEVMConnectors = evmConnectors.filter((connector) => { const isInstalled = isWalletInstalled(connector.id) return !isInstalled && isDesktopView }) const notDetectedSVMWallets = solanaWallets.filter((wallet) => { const isInstalled = wallet.adapter.readyState === WalletReadyState.Installed || wallet.adapter.readyState === WalletReadyState.Loadable return !isInstalled && isDesktopView }) const notDetectedCombinedWallets = combineWalletLists( notDetectedEVMConnectors, notDetectedUTXOConnectors, notDetectedSVMWallets ) installedCombinedWallets.sort(walletComparator) notDetectedCombinedWallets.sort(walletComparator) return { installedWallets: installedCombinedWallets, notDetectedWallets: notDetectedCombinedWallets, } }, [ bigmiAccount.connector?.id, bigmiConnectors, solanaWallets, wagmiAccount.connector?.id, wagmiConnectors, isDesktopView, walletConfig, ]) return data } // Ensure the walletComparator function is updated to handle CombinedWallet export const walletComparator = (a: CombinedWallet, b: CombinedWallet) => { const priorityA = getWalletPriority(a.id) const priorityB = getWalletPriority(b.id) if (priorityA !== priorityB) { return priorityA - priorityB } return a.id?.localeCompare(b.id) }