import { useEffect, useMemo } from 'react' import Wallet from '@project-serum/sol-wallet-adapter' import useLocalStorageState from './useLocalStorageState' import useMangoStore from '../stores/useMangoStore' import { notify } from '../utils/notifications' import { PhantomWalletAdapter, SlopeWalletAdapter, SolletExtensionAdapter, } from '../utils/wallet-adapters' import { WalletAdapter } from '../@types/types' import useInterval from './useInterval' import { useTranslation } from 'next-i18next' const SECONDS = 1000 const ASSET_URL = 'https://cdn.jsdelivr.net/gh/solana-labs/oyster@main/assets/wallets' export const WALLET_PROVIDERS = [ { name: 'Phantom', url: 'https://www.phantom.app', icon: `https://www.phantom.app/img/logo.png`, adapter: PhantomWalletAdapter, }, { name: 'Sollet.io', url: 'https://www.sollet.io', icon: `${ASSET_URL}/sollet.svg`, }, { name: 'Sollet Extension', url: 'https://www.sollet.io/extension', icon: `${ASSET_URL}/sollet.svg`, adapter: SolletExtensionAdapter as any, }, { name: 'Slope', url: 'https://www.slope.finance/#/wallet', icon: 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIHdpZHRoPSIxMjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGNpcmNsZSBjeD0iNjQiIGN5PSI2NCIgZmlsbD0iIzZlNjZmYSIgcj0iNjQiLz48ZyBmaWxsPSIjZmZmIj48cGF0aCBkPSJtMzUuMTk2MyA1NC4zOTk4aDE5LjJ2MTkuMmgtMTkuMnoiLz48cGF0aCBkPSJtNzMuNTk3IDU0LjM5OTgtMTkuMiAxOS4ydi0xOS4ybDE5LjItMTkuMnoiIGZpbGwtb3BhY2l0eT0iLjQiLz48cGF0aCBkPSJtNzMuNTk3IDczLjU5OTgtMTkuMiAxOS4ydi0xOS4ybDE5LjItMTkuMnoiIGZpbGwtb3BhY2l0eT0iLjc1Ii8+PHBhdGggZD0ibTczLjYwNCA1NC4zOTk4aDE5LjJ2MTkuMmgtMTkuMnoiLz48cGF0aCBkPSJtNTQuMzk2OCAzNS4yIDE5LjItMTkuMnYxOS4ybC0xOS4yIDE5LjJoLTE5LjJ6IiBmaWxsLW9wYWNpdHk9Ii43NSIvPjxwYXRoIGQ9Im03My41OTE1IDkyLjgtMTkuMiAxOS4ydi0xOS4ybDE5LjItMTkuMmgxOS4yeiIgZmlsbC1vcGFjaXR5PSIuNCIvPjwvZz48L3N2Zz4=', adapter: SlopeWalletAdapter, }, ] export const PROVIDER_LOCAL_STORAGE_KEY = 'walletProvider-0.1' export const DEFAULT_PROVIDER = WALLET_PROVIDERS[0] export default function useWallet() { const { t } = useTranslation('common') const setMangoStore = useMangoStore((state) => state.set) const { current: wallet, connected, providerUrl: selectedProviderUrl, } = useMangoStore((state) => state.wallet) const endpoint = useMangoStore((state) => state.connection.endpoint) const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current) const actions = useMangoStore((s) => s.actions) const [savedProviderUrl, setSavedProviderUrl] = useLocalStorageState( PROVIDER_LOCAL_STORAGE_KEY, DEFAULT_PROVIDER.url ) const provider = useMemo( () => WALLET_PROVIDERS.find(({ url }) => url === savedProviderUrl), [savedProviderUrl] ) useEffect(() => { if (selectedProviderUrl) { setSavedProviderUrl(selectedProviderUrl) } }, [selectedProviderUrl]) useEffect(() => { if (provider) { const updateWallet = () => { // hack to also update wallet synchronously in case it disconnects // eslint-disable-next-line react-hooks/exhaustive-deps const wallet = new (provider.adapter || Wallet)( savedProviderUrl, endpoint ) as WalletAdapter setMangoStore((state) => { state.wallet.current = wallet }) } if (document.readyState !== 'complete') { // wait to ensure that browser extensions are loaded const listener = () => { updateWallet() window.removeEventListener('load', listener) } window.addEventListener('load', listener) return () => window.removeEventListener('load', listener) } else { updateWallet() } } }, [provider, savedProviderUrl, endpoint]) useEffect(() => { if (!wallet) return wallet.on('connect', async () => { setMangoStore((state) => { state.wallet.connected = true }) // set connected before fetching data await actions.fetchAllMangoAccounts() actions.reloadOrders() actions.fetchTradeHistory() actions.fetchWalletTokens() notify({ title: t('wallet-connected'), description: t('connected-to') + wallet.publicKey.toString().substr(0, 5) + '...' + wallet.publicKey.toString().substr(-5), }) }) wallet.on('disconnect', () => { console.log('disconnecting wallet') setMangoStore((state) => { state.wallet.connected = false state.mangoAccounts = [] state.selectedMangoAccount.current = null state.tradeHistory = [] }) notify({ type: 'info', title: t('wallet-disconnected'), }) }) return () => { if (wallet && wallet.connected) { console.log('DISCONNECTING') wallet.disconnect() } setMangoStore((state) => { state.wallet.connected = false }) } }, [wallet, setMangoStore]) useInterval(() => { if (connected && mangoAccount) { actions.fetchWalletTokens() actions.fetchTradeHistory() } }, 90 * SECONDS) useInterval(() => { if (connected && mangoAccount) { actions.reloadMangoAccount() } }, 20 * SECONDS) return { connected, wallet } }