import type { WalletAdapter } from '@solana/wallet-adapter-base'; import { useWallet as useSolanaWallet } from '@solana/wallet-adapter-react'; import type { TonConnectUI } from '@tonconnect/ui'; import { toUserFriendlyAddress } from '@tonconnect/ui'; import { useMemo, useState } from 'react'; import type { Chain } from 'viem'; import type { Connector } from 'wagmi'; import { useAccount as useWagmiAccount } from 'wagmi'; import { useTon } from '../providers/WalletProvider/TVM/TVMBaseProvider.js'; import { ChainId } from '../types/base.js'; import { ChainType } from '../utils/chainType.js'; // @ts-ignore import { useWallet } from '@suiet/wallet-kit'; import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'; export interface AccountBase { address?: string; addresses?: readonly string[]; chain?: Chain; chainId?: number; chainType?: ChainType; isConnected: boolean; isConnecting: boolean; isDisconnected: boolean; isReconnecting: boolean; status: 'connected' | 'reconnecting' | 'connecting' | 'disconnected'; } export interface EVMAccount extends AccountBase { chainType: ChainType.EVM; connector?: Connector; } export interface SVMAccount extends AccountBase { chainType: ChainType.SVM; connector?: WalletAdapter; } export interface TONConnector extends TonConnectUI { name: string; icon: string; id: string; type: string; } export interface TVMAccount extends AccountBase { chainType: ChainType.TVM; connector: TONConnector; } export interface MOVEConnector { name: string; icon: string; id: string; type: string; } export interface MVMAccount extends AccountBase { chainType: ChainType.MVM; connector: MOVEConnector; } export interface EclipseAccount extends AccountBase { chainType: ChainType.ECLIPSE; connector?: WalletAdapter; } export interface DefaultAccount extends AccountBase { connector?: never; } export type Account = | EVMAccount | SVMAccount | DefaultAccount | TVMAccount | MVMAccount | EclipseAccount; export interface AccountResult { account: Account; /** * Connected accounts */ accounts: Account[]; } interface UseAccountArgs { chainType?: ChainType; } const defaultAccount: AccountBase = { isConnected: false, isConnecting: false, isReconnecting: false, isDisconnected: true, status: 'disconnected', }; /** * * @param args When we provide args we want to return either account with corresponding chainType or default disconnected one * @returns - Account result */ export const useAccount = (args?: UseAccountArgs): AccountResult => { const account = useWagmiAccount(); const { wallet, connected } = useSolanaWallet(); const [isTonConnected, setIsTonConnected] = useState(false); const { tonConnectUI } = useTon(); const userFriendlyAddress = tonConnectUI?.account?.address ? toUserFriendlyAddress(tonConnectUI.account.address, false) : ''; const { chains } = useWidgetConfig(); const suiWallet = useWallet(); // trigger re-render when tonConnectUI status changes tonConnectUI?.onStatusChange((wallet) => { if (wallet) { setIsTonConnected(true); } else { setIsTonConnected(false); } }); // We create a simple variable from the args object // to avoid re-render useMemo on every object reference change. const hasChainTypeArgs = Boolean(args); return useMemo(() => { const evm: Account = { ...account, chainType: ChainType.EVM }; const tvm: TVMAccount = { address: userFriendlyAddress, chainType: ChainType.TVM, chainId: ChainId.TON, connector: { ...tonConnectUI, name: 'Ton Connect', icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDU2IDU2IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1NiA1NjsiIHhtbDpzcGFjZT0icHJlc2VydmUiIGNsYXNzPSJtZGwtanMiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiMwMDg4Q0M7fQoJLnN0MXtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiNGRkZGRkY7fQo8L3N0eWxlPgo8Y2lyY2xlIGNsYXNzPSJzdDAiIGN4PSIyOCIgY3k9IjI4IiByPSIyOCIvPgo8cGF0aCBjbGFzcz0ic3QxIiBkPSJNMjAuMiwxOC41aDE1LjdjMC42LDAsMS4xLDAuMSwxLjcsMC40YzAuNywwLjMsMS4xLDAuOCwxLjMsMS4yYzAsMCwwLDAuMSwwLjEsMC4xYzAuMywwLjUsMC41LDEuMSwwLjUsMS44ICBjMCwwLjYtMC4xLDEuMi0wLjUsMS44YzAsMCwwLDAsMCwwbC05LjksMTdjLTAuMiwwLjQtMC42LDAuNi0xLjEsMC42Yy0wLjQsMC0wLjgtMC4yLTEuMS0wLjZsLTkuNy0xN2MwLDAsMCwwLDAsMCAgYy0wLjItMC40LTAuNi0wLjktMC42LTEuN2MtMC4xLTAuNywwLjEtMS4zLDAuNC0xLjljMC4zLTAuNiwwLjgtMS4xLDEuNS0xLjNDMTkuMSwxOC41LDE5LjgsMTguNSwyMC4yLDE4LjV6IE0yNi44LDIwLjloLTYuNiAgYy0wLjQsMC0wLjYsMC0wLjcsMC4xYy0wLjIsMC4xLTAuMywwLjItMC40LDAuNEMxOSwyMS41LDE5LDIxLjcsMTksMjEuOWMwLDAuMSwwLjEsMC4yLDAuMywwLjZjMCwwLDAsMCwwLDBsNy41LDEzVjIwLjl6ICAgTTI5LjIsMjAuOXYxNC43bDcuNi0xMy4xYzAuMS0wLjIsMC4xLTAuNCwwLjEtMC42YzAtMC4yLDAtMC40LTAuMS0wLjVjLTAuMS0wLjEtMC4xLTAuMi0wLjItMC4yYzAsMC0wLjEtMC4xLTAuMS0wLjEgIGMtMC4yLTAuMS0wLjQtMC4xLTAuNy0wLjFIMjkuMnoiLz4KPC9zdmc+', type: 'TVM', id: 'tvm', } as any, isConnected: Boolean(userFriendlyAddress), isConnecting: false, isReconnecting: false, isDisconnected: !wallet, status: tonConnectUI?.connected ? 'connected' : 'disconnected', }; const mvm: MVMAccount = { address: suiWallet?.address, chainType: ChainType.MVM, chainId: ChainId.MOVE, connector: { ...suiWallet, name: 'Sui Connect', icon: 'https://strapi-dev.scand.app/uploads/sui_c07df05f00.png', type: 'MVM', id: 'mvm', } as any, isConnected: suiWallet?.connected, isConnecting: false, isReconnecting: false, isDisconnected: !suiWallet?.connected, status: suiWallet?.status, }; const svm: Account = wallet?.adapter?.publicKey && connected && chains?.types?.allow?.includes(ChainType.SVM) ? { address: wallet?.adapter.publicKey.toString(), chainId: ChainId.SOL, chainType: ChainType.SVM, connector: wallet?.adapter, isConnected: Boolean(wallet?.adapter.publicKey), isConnecting: false, isReconnecting: false, isDisconnected: !wallet, status: 'connected', } : { chainType: ChainType.SVM, isConnected: false, isConnecting: false, isReconnecting: false, isDisconnected: true, status: 'disconnected', }; const eclipse: EclipseAccount = wallet?.adapter?.publicKey && connected && chains?.types?.allow?.includes(ChainType.ECLIPSE) ? { address: wallet?.adapter.publicKey.toString(), chainType: ChainType.ECLIPSE, chainId: ChainId.ECLIPSE, connector: wallet?.adapter, isConnected: Boolean(wallet?.adapter.publicKey), isConnecting: false, isReconnecting: false, isDisconnected: !wallet, status: 'connected', } : { chainType: ChainType.ECLIPSE, isConnected: false, isConnecting: false, isReconnecting: false, isDisconnected: true, status: 'disconnected', }; const accounts = [evm, svm, tvm, mvm, eclipse]; const connectedAccounts = [evm, svm, tvm, mvm, eclipse].filter( (account) => account.isConnected, ); return { account: accounts.find( (account) => (!hasChainTypeArgs || account.chainType === args?.chainType) && account.isConnected && account.address, ) ?? defaultAccount, // We need to return only connected account list accounts: connectedAccounts, }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [ connected, wallet, account, args?.chainType, hasChainTypeArgs, isTonConnected, userFriendlyAddress, suiWallet, ]); };