diff --git a/components/BorrowForm.tsx b/components/BorrowForm.tsx index e3a9e9c3..f8bf2372 100644 --- a/components/BorrowForm.tsx +++ b/components/BorrowForm.tsx @@ -35,7 +35,6 @@ import useMangoAccount from 'hooks/useMangoAccount' import useMangoGroup from 'hooks/useMangoGroup' import TokenVaultWarnings from '@components/shared/TokenVaultWarnings' import { useWallet } from '@solana/wallet-adapter-react' -import { useEnhancedWallet } from './wallet/EnhancedWalletProvider' import FormatNumericValue from './shared/FormatNumericValue' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' @@ -63,8 +62,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) { const [showTokenList, setShowTokenList] = useState(false) const [sizePercentage, setSizePercentage] = useState('') const { mangoAccount } = useMangoAccount() - const { connected, publicKey } = useWallet() - const { handleConnect } = useEnhancedWallet() + const { connected, publicKey, connect } = useWallet() const banks = useBanksWithBalances('maxBorrow') const bank = useMemo(() => { @@ -329,7 +327,7 @@ function BorrowForm({ onSuccess, token }: BorrowFormProps) { ) : null} + )} diff --git a/components/WithdrawForm.tsx b/components/WithdrawForm.tsx index f350f68c..9a226485 100644 --- a/components/WithdrawForm.tsx +++ b/components/WithdrawForm.tsx @@ -30,7 +30,6 @@ import useMangoAccount from 'hooks/useMangoAccount' import useMangoGroup from 'hooks/useMangoGroup' import TokenVaultWarnings from '@components/shared/TokenVaultWarnings' import { useWallet } from '@solana/wallet-adapter-react' -import { useEnhancedWallet } from './wallet/EnhancedWalletProvider' import { floorToDecimal } from 'utils/numbers' import BankAmountWithValue from './shared/BankAmountWithValue' import useBanksWithBalances from 'hooks/useBanksWithBalances' @@ -55,8 +54,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) { const [showTokenList, setShowTokenList] = useState(false) const [sizePercentage, setSizePercentage] = useState('') const { mangoAccount } = useMangoAccount() - const { connected } = useWallet() - const { handleConnect } = useEnhancedWallet() + const { connect, connected } = useWallet() const banks = useBanksWithBalances('maxWithdraw') const bank = useMemo(() => { @@ -259,7 +257,7 @@ function WithdrawForm({ onSuccess, token }: WithdrawFormProps) { ) : null} - {wallet.connected ? ( + {connected ? ( ) : ( - )} diff --git a/components/governance/ListToken/ListToken.tsx b/components/governance/ListToken/ListToken.tsx index f60c8aa0..5b44c48c 100644 --- a/components/governance/ListToken/ListToken.tsx +++ b/components/governance/ListToken/ListToken.tsx @@ -32,7 +32,6 @@ import Loading from '@components/shared/Loading' import ListingSuccess from '../ListingSuccess' import InlineNotification from '@components/shared/InlineNotification' import { Disclosure } from '@headlessui/react' -import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider' import { abbreviateAddress } from 'utils/formatting' import { formatNumericValue } from 'utils/numbers' import useMangoGroup from 'hooks/useMangoGroup' @@ -86,12 +85,11 @@ const defaultTokenListFormValues: TokenListForm = { const TWENTY_K_USDC_BASE = '20000000000' const ListToken = ({ goBack }: { goBack: () => void }) => { - const wallet = useWallet() + const { connect, publicKey, connected, wallet } = useWallet() const { jupiterTokens } = useJupiterMints() const connection = mangoStore((s) => s.connection) const client = mangoStore((s) => s.client) const { group } = useMangoGroup() - const { handleConnect } = useEnhancedWallet() const voter = GovernanceStore((s) => s.voter) const vsrClient = GovernanceStore((s) => s.vsrClient) const governances = GovernanceStore((s) => s.governances) @@ -218,9 +216,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { (amount: number, tokenMint: PublicKey, mode: 'ExactIn' | 'ExactOut') => { const SLIPPAGE_BPS = 50 const FEE = 0 - const walletForCheck = wallet.publicKey - ? wallet.publicKey?.toBase58() - : emptyPk + const walletForCheck = publicKey ? publicKey?.toBase58() : emptyPk return handleGetRoutes( USDC_MINT, @@ -233,7 +229,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { 'JUPITER' ) }, - [wallet.publicKey] + [publicKey] ) const handleLiqudityCheck = useCallback( @@ -298,7 +294,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { }) } }, - [t, wallet.publicKey] + [t, handleGetRoutesWithFixedArgs] ) const handleGetPoolParams = (routes: never[] | RouteInfo[]) => { @@ -387,8 +383,8 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { if (Object.keys(invalidFields).length) { return } - if (!wallet?.publicKey || !vsrClient || !connectionContext) return - await getCurrentVotingPower(wallet.publicKey, vsrClient, connectionContext) + if (!publicKey || !vsrClient || !connectionContext) return + await getCurrentVotingPower(publicKey, vsrClient, connectionContext) if (voter.voteWeight.cmp(minVoterWeight) === -1) { notify({ @@ -960,7 +956,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => { - {wallet.connected ? ( + {connected ? ( ) : ( - )} diff --git a/components/modals/CreateOpenbookMarketModal.tsx b/components/modals/CreateOpenbookMarketModal.tsx index cb586a09..1690b90d 100644 --- a/components/modals/CreateOpenbookMarketModal.tsx +++ b/components/modals/CreateOpenbookMarketModal.tsx @@ -13,7 +13,6 @@ import { LAMPORTS_PER_SOL, PublicKey, Transaction } from '@solana/web3.js' import { MARKET_STATE_LAYOUT_V2 } from '@project-serum/serum' import { notify } from 'utils/notifications' import InlineNotification from '@components/shared/InlineNotification' -import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider' type CreateObMarketForm = { programId: string @@ -63,8 +62,7 @@ const CreateOpenbookMarketModal = ({ }: ModalProps & CreateOpenbookMarketModalProps) => { const { t } = useTranslation(['governance']) const connection = mangoStore((s) => s.connection) - const wallet = useWallet() - const { handleConnect } = useEnhancedWallet() + const { connect, signAllTransactions, connected, publicKey } = useWallet() const [form, setForm] = useState({ ...defaultFormValues }) const [formErrors, setFormErrors] = useState({}) @@ -77,7 +75,7 @@ const CreateOpenbookMarketModal = ({ } const handleCreate = async () => { - if (!wallet || !wallet.signAllTransactions) { + if (!publicKey || !signAllTransactions) { return } let sig = '' @@ -85,7 +83,7 @@ const CreateOpenbookMarketModal = ({ try { const ixObj = await makeCreateOpenBookMarketInstructionSimple({ connection, - wallet: wallet.publicKey!, + wallet: publicKey, baseInfo: { mint: new PublicKey(baseMint), decimals: baseDecimals, @@ -107,11 +105,11 @@ const CreateOpenbookMarketModal = ({ tx.add(...chunk.instructions) tx.lastValidBlockHeight = latestBlockhash.lastValidBlockHeight tx.recentBlockhash = latestBlockhash.blockhash - tx.feePayer = wallet.publicKey! + tx.feePayer = publicKey tx.sign(...chunk.signers) transactions.push(tx) } - const signedTransactions = await wallet.signAllTransactions(transactions) + const signedTransactions = await signAllTransactions(transactions) for (const tx of signedTransactions) { const rawTransaction = tx.serialize() @@ -257,7 +255,7 @@ const CreateOpenbookMarketModal = ({ )} - {wallet.connected ? ( + {connected ? ( )} diff --git a/components/modals/UserSetupModal.tsx b/components/modals/UserSetupModal.tsx index e8177584..d83cd6f4 100644 --- a/components/modals/UserSetupModal.tsx +++ b/components/modals/UserSetupModal.tsx @@ -3,6 +3,7 @@ import { ArrowDownTrayIcon, ArrowTopRightOnSquareIcon, CheckCircleIcon, + ChevronDownIcon, ExclamationCircleIcon, PencilIcon, } from '@heroicons/react/20/solid' @@ -26,7 +27,6 @@ import ActionTokenList from '../account/ActionTokenList' import ButtonGroup from '../forms/ButtonGroup' import Input from '../forms/Input' import Label from '../forms/Label' -import WalletIcon from '../icons/WalletIcon' // import ParticlesBackground from '../ParticlesBackground' // import EditNftProfilePic from '../profile/EditNftProfilePic' // import EditProfileForm from '../profile/EditProfileForm' @@ -35,7 +35,6 @@ import InlineNotification from '../shared/InlineNotification' import Loading from '../shared/Loading' import MaxAmountButton from '../shared/MaxAmountButton' import SolBalanceWarnings from '../shared/SolBalanceWarnings' -import { useEnhancedWallet } from '../wallet/EnhancedWalletProvider' import Modal from '../shared/Modal' import NumberFormat, { NumberFormatValues } from 'react-number-format' import { withValueLimit } from '@components/swap/SwapForm' @@ -46,6 +45,7 @@ import ColorBlur from '@components/ColorBlur' import useLocalStorageState from 'hooks/useLocalStorageState' import { ACCEPT_TERMS_KEY } from 'utils/constants' import { ACCOUNT_ACTIONS_NUMBER_FORMAT_CLASSES } from '@components/BorrowForm' +import { WalletReadyState } from '@solana/wallet-adapter-base' const UserSetupModal = ({ isOpen, @@ -66,10 +66,27 @@ const UserSetupModal = ({ const [submitDeposit, setSubmitDeposit] = useState(false) const [sizePercentage, setSizePercentage] = useState('') // const [showEditProfilePic, setShowEditProfilePic] = useState(false) - const { handleConnect } = useEnhancedWallet() const { maxSolDeposit } = useSolBalance() const banks = useBanksWithBalances('walletBalance') const [, setAcceptTerms] = useLocalStorageState(ACCEPT_TERMS_KEY, '') + const [walletsToDisplay, setWalletstoDisplay] = useState<'default' | 'all'>( + 'default' + ) + + const walletsDisplayed = useMemo(() => { + const firstFive = wallets.slice(0, 5) + const detectedWallets = wallets.filter( + (w) => w.readyState === WalletReadyState.Installed + ) + + if (walletsToDisplay === 'default') { + return detectedWallets.length > firstFive.length + ? detectedWallets + : firstFive + } else { + return wallets + } + }, [walletsToDisplay, wallets]) useEffect(() => { if (connected) { @@ -279,44 +296,45 @@ const UserSetupModal = ({ {t('onboarding:choose-wallet')}

- {wallets?.map((w) => ( + {walletsDisplayed?.map((w) => ( ))}
- + + ) : null} ) : null} diff --git a/components/shared/ConnectEmptyState.tsx b/components/shared/ConnectEmptyState.tsx index 672dc4ae..3ec74750 100644 --- a/components/shared/ConnectEmptyState.tsx +++ b/components/shared/ConnectEmptyState.tsx @@ -1,19 +1,17 @@ import WalletIcon from '@components/icons/WalletIcon' -import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider' import { LinkIcon } from '@heroicons/react/20/solid' -import mangoStore from '@store/mangoStore' import { useTranslation } from 'next-i18next' import Button from './Button' +import { useWallet } from '@solana/wallet-adapter-react' const ConnectEmptyState = ({ text }: { text: string }) => { const { t } = useTranslation('common') - const { handleConnect } = useEnhancedWallet() - const groupLoaded = mangoStore((s) => s.groupLoaded) + const { connect } = useWallet() return (

{text}

- + ))} + + + )} -
-
- {t('connect')} -
- -
- {preselectedWalletName} -
+ + ) : ( +
- - -
+ + )} + ) } diff --git a/components/wallet/ConnectedMenu.tsx b/components/wallet/ConnectedMenu.tsx index 0352d716..f8f90768 100644 --- a/components/wallet/ConnectedMenu.tsx +++ b/components/wallet/ConnectedMenu.tsx @@ -4,7 +4,7 @@ import { CurrencyDollarIcon, UserCircleIcon, } from '@heroicons/react/20/solid' -import { useWallet, Wallet } from '@solana/wallet-adapter-react' +import { useWallet } from '@solana/wallet-adapter-react' import { useTranslation } from 'next-i18next' import { Fragment, useCallback, useEffect, useState } from 'react' import mangoStore from '@store/mangoStore' @@ -15,29 +15,25 @@ import { useViewport } from 'hooks/useViewport' import { breakpoints } from '../../utils/theme' import EditProfileModal from '@components/modals/EditProfileModal' import MangoAccountsListModal from '@components/modals/MangoAccountsListModal' +import { TV_USER_ID_KEY } from 'utils/constants' +import useLocalStorageState from 'hooks/useLocalStorageState' + +const set = mangoStore.getState().set +const actions = mangoStore.getState().actions const ConnectedMenu = () => { const { t } = useTranslation('common') const { publicKey, disconnect, wallet } = useWallet() const { width } = useViewport() - + const [tvUserId, setTvUserId] = useLocalStorageState(TV_USER_ID_KEY, '') const [showEditProfileModal, setShowEditProfileModal] = useState(false) const [showMangoAccountsModal, setShowMangoAccountsModal] = useState(false) - const set = mangoStore((s) => s.set) - const actions = mangoStore.getState().actions // const profileDetails = mangoStore((s) => s.profile.details) const loadProfileDetails = mangoStore((s) => s.profile.loadDetails) - + const groupLoaded = mangoStore((s) => s.groupLoaded) const isMobile = width ? width < breakpoints.md : false - const onConnectFetchAccountData = async (wallet: Wallet) => { - if (!wallet.adapter.publicKey) return - await actions.fetchMangoAccounts(wallet.adapter.publicKey) - // actions.fetchTourSettings(wallet.adapter.publicKey?.toString() as string) - actions.fetchWalletTokens(wallet.adapter.publicKey) - } - const handleDisconnect = useCallback(() => { set((state) => { state.activityFeed.feed = [] @@ -52,20 +48,20 @@ const ConnectedMenu = () => { type: 'info', title: t('wallet-disconnected'), }) - }, [set, t, disconnect]) + }, [t, disconnect]) useEffect(() => { - const handleGetWalletMangoData = async (wallet: Wallet) => { - const actions = mangoStore.getState().actions - await actions.connectMangoClientWithWallet(wallet) - await onConnectFetchAccountData(wallet) - } - - if (publicKey && wallet) { + if (publicKey && wallet && groupLoaded) { + actions.connectMangoClientWithWallet(wallet) + actions.fetchMangoAccounts(publicKey) + // actions.fetchTourSettings(publicKey?.toString() as string) actions.fetchProfileDetails(publicKey.toString()) - handleGetWalletMangoData(wallet) + actions.fetchWalletTokens(publicKey) + if (!tvUserId) { + setTvUserId(publicKey.toString()) + } } - }, [publicKey, actions, wallet]) + }, [publicKey, wallet, groupLoaded, tvUserId, setTvUserId]) return ( <> diff --git a/components/wallet/EnhancedWalletProvider.tsx b/components/wallet/EnhancedWalletProvider.tsx deleted file mode 100644 index c72a8aab..00000000 --- a/components/wallet/EnhancedWalletProvider.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { SolanaMobileWalletAdapter } from '@solana-mobile/wallet-adapter-mobile' -import { WalletName, WalletReadyState } from '@solana/wallet-adapter-base' -import { useWallet, Wallet } from '@solana/wallet-adapter-react' -import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base' -import React, { - createContext, - ReactNode, - useCallback, - useContext, - useEffect, - useMemo, -} from 'react' -import { notify } from 'utils/notifications' -import useLocalStorageState from 'hooks/useLocalStorageState' -import { TV_USER_ID_KEY } from 'utils/constants' - -interface EnhancedWalletContextState { - displayedWallets: Wallet[] - preselectedWalletName: string - handleSelect: (name: WalletName | null) => void - handleConnect: () => Promise -} - -const EnhancedWalletContext = createContext( - {} as EnhancedWalletContextState -) - -export function useEnhancedWallet(): EnhancedWalletContextState { - return useContext(EnhancedWalletContext) -} - -export default function EnhancedWalletProvider({ - children, -}: { - children: ReactNode -}) { - const { wallets, select, wallet, connect } = useWallet() - - const displayedWallets = useMemo( - () => - wallets.slice().sort(({ adapter: a }, { adapter: b }) => { - if (a instanceof SolanaMobileWalletAdapter) { - if (b instanceof SolanaMobileWalletAdapter) return 0 - return -1 - } else if (b instanceof SolanaMobileWalletAdapter) { - return 1 - } - - if (a instanceof StandardWalletAdapter) { - if (b instanceof StandardWalletAdapter) return 0 - return -1 - } else if (b instanceof StandardWalletAdapter) { - return 1 - } - - if (a.readyState === b.readyState) return 0 - if (a.readyState === WalletReadyState.Installed) return -1 - if (b.readyState === WalletReadyState.Installed) return 1 - return 0 - }), - [wallets] - ) - - const [preselectedWalletName, setPreselectedWalletName] = - useLocalStorageState('preselectedWalletName', '') - - const [tvUserId, setTvUserId] = useLocalStorageState(TV_USER_ID_KEY, '') - - useEffect(() => { - if (wallet) { - setPreselectedWalletName(wallet.adapter.name) - } else { - const hasInstalledWallet = displayedWallets.find( - (w) => w.readyState === 'Installed' - ) - if (hasInstalledWallet) { - setPreselectedWalletName(hasInstalledWallet.adapter.name) - } else { - setPreselectedWalletName('Phantom') - } - } - }, [displayedWallets, wallet, setPreselectedWalletName]) - - useEffect(() => { - if (!wallet && preselectedWalletName) { - const wallet = wallets.find( - (w) => w.adapter.name === preselectedWalletName - ) - if (wallet) { - select(wallet.adapter.name) - } - } - }, [wallet, preselectedWalletName, wallets, select]) - - const handleSelect = useCallback( - (name: WalletName | null) => { - setPreselectedWalletName(name) - select(name) - }, - [setPreselectedWalletName, select] - ) - - const handleConnect = useCallback(async () => { - if (wallet) { - try { - console.log('connecting') - await connect() - if (!tvUserId && wallet.adapter.publicKey) { - setTvUserId(wallet.adapter.publicKey.toString()) - } - } catch (e) { - // Error will be handled by WalletProvider#onError - select(null) - } - } else if (preselectedWalletName) { - const adapter = wallets.find( - ({ adapter }) => adapter.name === preselectedWalletName - )?.adapter - - if (!adapter) { - setPreselectedWalletName(null) - return - } - - if ( - adapter.readyState === WalletReadyState.Installed || - adapter.readyState === WalletReadyState.Loadable - ) { - await select(adapter.name) - } else { - notify({ - title: `${adapter.name} Error`, - type: 'error', - description: `Please install ${adapter.name} and then reload this page.`, - }) - if (typeof window !== 'undefined') { - window.open(adapter.url, '_blank') - } - } - } - }, [ - wallets, - select, - wallet, - connect, - preselectedWalletName, - setPreselectedWalletName, - ]) - - return ( - - {children} - - ) -} diff --git a/components/wallet/WalletSelect.tsx b/components/wallet/WalletSelect.tsx deleted file mode 100644 index 0ec71a9f..00000000 --- a/components/wallet/WalletSelect.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { Fragment } from 'react' -import { ChevronDownIcon } from '@heroicons/react/20/solid' -import { Popover, Transition } from '@headlessui/react' -import { useEnhancedWallet } from './EnhancedWalletProvider' -import useMangoGroup from 'hooks/useMangoGroup' - -const WalletSelect = () => { - const { displayedWallets, handleSelect } = useEnhancedWallet() - const { group } = useMangoGroup() - - return ( - - {({ open }) => ( - <> - - - - - - {displayedWallets?.map((wallet, index) => ( - - ))} - - - - )} - - ) -} - -export default WalletSelect diff --git a/pages/_app.tsx b/pages/_app.tsx index 200eb216..81a488b1 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -17,6 +17,14 @@ import { PhantomWalletAdapter, SolflareWalletAdapter, GlowWalletAdapter, + BackpackWalletAdapter, + BraveWalletAdapter, + CoinbaseWalletAdapter, + MathWalletAdapter, + Coin98WalletAdapter, + CloverWalletAdapter, + LedgerWalletAdapter, + ExodusWalletAdapter, } from '@solana/wallet-adapter-wallets' import { clusterApiUrl } from '@solana/web3.js' import TransactionNotification from '@components/notifications/TransactionNotification' @@ -26,7 +34,6 @@ import Layout from '../components/Layout' import { ViewportProvider } from '../hooks/useViewport' import MangoProvider from '@components/MangoProvider' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import EnhancedWalletProvider from '@components/wallet/EnhancedWalletProvider' import { notify } from 'utils/notifications' import { useRouter } from 'next/router' import useSelectedMarket from 'hooks/useSelectedMarket' @@ -36,16 +43,15 @@ import { PerpMarket } from '@blockworks-foundation/mango-v4' import { getDecimalCount } from 'utils/numbers' import { THEME_KEY } from 'utils/constants' -// Do not add hooks to this component that will cause unnecessary rerenders -// Top level state hydrating/updating should go in MangoProvider - -// Create a client +// init react-query export const queryClient = new QueryClient() const metaTitle = 'Mango Markets – Safer. Smarter. Faster.' const metaDescription = 'A magical new way to interact with DeFi. Groundbreaking safety features designed to keep your funds secure. The easiest way to margin trade any token pair. All powered by flashloans.' +// Do not add hooks to this component, that will cause unnecessary rerenders +// Top level state hydrating/updating should go in MangoProvider function MyApp({ Component, pageProps }: AppProps) { const network = WalletAdapterNetwork.Mainnet const endpoint = useMemo(() => clusterApiUrl(network), [network]) @@ -53,7 +59,15 @@ function MyApp({ Component, pageProps }: AppProps) { () => [ new PhantomWalletAdapter(), new SolflareWalletAdapter(), + new BackpackWalletAdapter(), new GlowWalletAdapter(), + new BraveWalletAdapter(), + new CoinbaseWalletAdapter(), + new MathWalletAdapter(), + new Coin98WalletAdapter(), + new CloverWalletAdapter(), + new LedgerWalletAdapter(), + new ExodusWalletAdapter(), ], [] ) @@ -100,21 +114,16 @@ function MyApp({ Component, pageProps }: AppProps) { - - - - - - - - - - - - + + + + + + + + + + diff --git a/store/mangoStore.ts b/store/mangoStore.ts index 087fabab..209f573d 100644 --- a/store/mangoStore.ts +++ b/store/mangoStore.ts @@ -42,11 +42,9 @@ import { RPC_PROVIDER_KEY, } from '../utils/constants' import { - AccountPerformanceData, ActivityFeed, EmptyObject, OrderbookL2, - PerformanceDataItem, PerpStatsItem, PerpTradeHistory, SerumEvent, diff --git a/utils/index.ts b/utils/index.ts index de0b7e5a..92a54322 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -44,3 +44,14 @@ export const copyToClipboard = (copyThis: string) => { document.execCommand('copy') document.body.removeChild(el) } + +export function getNetworkInfo() { + const connection = + (navigator as any).connection || + (navigator as any).mozConnection || + (navigator as any).webkitConnection + if (connection) { + return connection.effectiveType + } + return 'unknown' +}