migrate to wallet-adapter only; use autoconnect

This commit is contained in:
tjs 2023-07-20 19:07:59 -04:00
parent cf3d0f7e14
commit 4bb2c0016e
21 changed files with 236 additions and 433 deletions

View File

@ -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}
</div>
<Button
onClick={connected ? handleBorrow : handleConnect}
onClick={connected ? handleBorrow : connect}
className="flex w-full items-center justify-center"
disabled={connected && (!inputAmount || showInsufficientBalance)}
size="large"

View File

@ -25,7 +25,6 @@ import MaxAmountButton from '@components/shared/MaxAmountButton'
import Tooltip from '@components/shared/Tooltip'
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
import { useEnhancedWallet } from './wallet/EnhancedWalletProvider'
import useSolBalance from 'hooks/useSolBalance'
import FormatNumericValue from './shared/FormatNumericValue'
import Decimal from 'decimal.js'
@ -72,7 +71,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
)
const [showTokenList, setShowTokenList] = useState(false)
const [sizePercentage, setSizePercentage] = useState('')
const { handleConnect } = useEnhancedWallet()
const { connect } = useWallet()
const { maxSolDeposit } = useSolBalance()
const banks = useBanksWithBalances('walletBalance')
@ -272,7 +271,7 @@ function DepositForm({ onSuccess, token }: DepositFormProps) {
) : null}
</div>
<Button
onClick={connected ? handleDeposit : handleConnect}
onClick={connected ? handleDeposit : connect}
className="flex w-full items-center justify-center"
disabled={connected && (!inputAmount || showInsufficientBalance)}
size="large"

View File

@ -10,9 +10,7 @@ import {
import { ArrowPathIcon, ChevronRightIcon } from '@heroicons/react/20/solid'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from '../utils/theme'
import mangoStore from '@store/mangoStore'
import BottomBar from './mobile/BottomBar'
import BounceLoader from './shared/BounceLoader'
import TopBar from './TopBar'
import useLocalStorageState from '../hooks/useLocalStorageState'
import { ACCEPT_TERMS_KEY, SIDEBAR_COLLAPSE_KEY } from '../utils/constants'
@ -75,7 +73,6 @@ const Layout = ({ children }: { children: ReactNode }) => {
<div className="fixed z-30">
<SuccessParticles />
</div>
<MangoAccountLoadingOverlay />
<div className="flex-grow bg-th-bkg-1 text-th-fgd-2 transition-all">
<div className="fixed bottom-0 left-0 z-20 w-full md:hidden">
<BottomBar />
@ -119,21 +116,6 @@ const Layout = ({ children }: { children: ReactNode }) => {
export default Layout
const MangoAccountLoadingOverlay = () => {
const { connected } = useWallet()
const loadingMangoAccount = mangoStore((s) => s.mangoAccount.initialLoad)
return (
<>
{connected && loadingMangoAccount ? (
<div className="fixed z-30 flex h-screen w-full items-center justify-center bg-[rgba(0,0,0,0.7)]">
<BounceLoader />
</div>
) : null}
</>
)
}
const TermsOfUse = () => {
const { connected } = useWallet()
const [acceptTerms, setAcceptTerms] = useLocalStorageState(

View File

@ -5,6 +5,7 @@ import { useRouter } from 'next/router'
import { MangoAccount } from '@blockworks-foundation/mango-v4'
import useMangoAccount from 'hooks/useMangoAccount'
import useInterval from './shared/useInterval'
import { getNetworkInfo } from 'utils'
const set = mangoStore.getState().set
const actions = mangoStore.getState().actions
@ -48,6 +49,7 @@ const HydrateStore = () => {
useInterval(async () => {
const actions = mangoStore.getState().actions
actions.loadMarketFills()
console.log('connection', getNetworkInfo())
}, 30000)
// The websocket library solana/web3.js uses closes its websocket connection when the subscription list

View File

@ -12,12 +12,9 @@ import { useTranslation } from 'next-i18next'
import WalletIcon from './icons/WalletIcon'
import Button from './shared/Button'
import ConnectedMenu from './wallet/ConnectedMenu'
import { ConnectWalletButton } from './wallet/ConnectWalletButton'
import { IS_ONBOARDED_KEY } from '../utils/constants'
import useLocalStorageState from '../hooks/useLocalStorageState'
import ConnectWalletButton from './wallet/ConnectWalletButton'
import CreateAccountModal from './modals/CreateAccountModal'
import { useRouter } from 'next/router'
import UserSetupModal from './modals/UserSetupModal'
import SolanaTps from './SolanaTps'
import useMangoAccount from 'hooks/useMangoAccount'
import useOnlineStatus from 'hooks/useOnlineStatus'
@ -30,24 +27,31 @@ import useUnownedAccount from 'hooks/useUnownedAccount'
import NotificationsButton from './notifications/NotificationsButton'
import Tooltip from './shared/Tooltip'
import { copyToClipboard } from 'utils'
import UserSetupModal from './modals/UserSetupModal'
import { IS_ONBOARDED_KEY } from 'utils/constants'
import useLocalStorageState from 'hooks/useLocalStorageState'
const TopBar = () => {
const { t } = useTranslation('common')
const { mangoAccount } = useMangoAccount()
const { connected } = useWallet()
const [isOnboarded, setIsOnboarded] = useLocalStorageState(IS_ONBOARDED_KEY)
const [action, setAction] = useState<'deposit' | 'withdraw'>('deposit')
const [showUserSetup, setShowUserSetup] = useState(false)
const [copied, setCopied] = useState('')
const [showDepositWithdrawModal, setShowDepositWithdrawModal] =
useState(false)
const [showCreateAccountModal, setShowCreateAccountModal] = useState(false)
const isOnline = useOnlineStatus()
const router = useRouter()
const { query } = router
const { width } = useViewport()
const isMobile = width ? width < breakpoints.sm : false
const { isUnownedAccount } = useUnownedAccount()
const [showUserSetup, setShowUserSetup] = useState(false)
const [, setIsOnboarded] = useLocalStorageState(IS_ONBOARDED_KEY)
const handleCloseSetup = useCallback(() => {
setShowUserSetup(false)
@ -193,18 +197,8 @@ const TopBar = () => {
<AccountsButton />
<ConnectedMenu />
</div>
) : isOnboarded ? (
<ConnectWalletButton />
) : (
<button
className="relative h-16 rounded-none bg-th-bkg-2 bg-gradient-to-bl px-6 font-display text-base text-th-fgd-1 before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-th-bkg-4 before:to-transparent before:opacity-0 hover:cursor-pointer hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100"
onClick={handleShowSetup}
>
<div className="relative z-10 flex items-center justify-center">
<WalletIcon className="mr-2 h-5 w-5 flex-shrink-0" />
{t('connect')}
</div>
</button>
<ConnectWalletButton handleShowSetup={handleShowSetup} />
)}
</div>
</div>

View File

@ -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}
</div>
<Button
onClick={connected ? handleWithdraw : handleConnect}
onClick={connected ? handleWithdraw : connect}
className="flex w-full items-center justify-center"
size="large"
disabled={

View File

@ -30,7 +30,6 @@ import ListingSuccess from '../ListingSuccess'
import { formatTokenSymbol } from 'utils/tokens'
import OnBoarding from '../OnBoarding'
import { calculateTradingParameters } from 'utils/governance/listingTools'
import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider'
import { tryGetPubKey } from 'utils/governance/tools'
type FormErrors = Partial<Record<keyof ListMarketForm, string>>
@ -58,8 +57,7 @@ const defaultFormValues: ListMarketForm = {
}
const ListMarket = ({ goBack }: { goBack: () => void }) => {
const wallet = useWallet()
const { handleConnect } = useEnhancedWallet()
const { connected, wallet, connect } = useWallet()
const { t } = useTranslation(['governance', 'trade'])
const { group } = useMangoGroup()
const connection = mangoStore((s) => s.connection)
@ -579,7 +577,7 @@ const ListMarket = ({ goBack }: { goBack: () => void }) => {
>
{t('cancel')}
</Button>
{wallet.connected ? (
{connected ? (
<Button
onClick={handlePropose}
disabled={proposing || !marketPk}
@ -592,7 +590,7 @@ const ListMarket = ({ goBack }: { goBack: () => void }) => {
)}
</Button>
) : (
<Button onClick={handleConnect} size="large">
<Button onClick={connect} size="large">
{t('connect-wallet')}
</Button>
)}

View File

@ -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 }) => {
<Button secondary onClick={cancel} size="large">
{t('cancel')}
</Button>
{wallet.connected ? (
{connected ? (
<Button
className="flex w-full items-center justify-center sm:w-44"
onClick={propose}
@ -982,7 +978,7 @@ const ListToken = ({ goBack }: { goBack: () => void }) => {
)}
</Button>
) : (
<Button onClick={handleConnect} size="large">
<Button onClick={connect} size="large">
{t('connect-wallet')}
</Button>
)}

View File

@ -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<FormErrors>({})
@ -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 = ({
)}
</div>
</div>
{wallet.connected ? (
{connected ? (
<Button
className="mt-6 w-full"
onClick={handleCreate}
@ -267,7 +265,7 @@ const CreateOpenbookMarketModal = ({
{t('create')}
</Button>
) : (
<Button className="mt-6 w-full" onClick={handleConnect} size="large">
<Button className="mt-6 w-full" onClick={connect} size="large">
{t('connect-wallet')}
</Button>
)}

View File

@ -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')}
</p>
<div className="space-y-2">
{wallets?.map((w) => (
{walletsDisplayed?.map((w) => (
<button
className={`col-span-1 w-full rounded-md border py-3 px-4 text-base font-normal focus:outline-none md:hover:cursor-pointer md:hover:border-th-fgd-4 ${
w.adapter.name === wallet?.adapter.name
? 'border-th-active text-th-fgd-1 md:hover:border-th-active'
: 'border-th-bkg-4 text-th-fgd-4'
: 'border-th-bkg-4 text-th-fgd-2'
}`}
onClick={() => {
select(w.adapter.name)
}}
key={w.adapter.name}
>
<div className="flex items-center">
<img
src={w.adapter.icon}
className="mr-2 h-5 w-5"
alt={`${w.adapter.name} icon`}
/>
{w.adapter.name}
<div className="flex items-center justify-between">
<div className="flex items-center">
<img
src={w.adapter.icon}
className="mr-2 h-5 w-5"
alt={`${w.adapter.name} icon`}
/>
<div className="ml-2">{w.adapter.name}</div>
</div>
{w.adapter.readyState === WalletReadyState.Installed ? (
<div className="text-xs">Detected</div>
) : null}
</div>
</button>
))}
</div>
<Button
className="mt-10 flex items-center justify-center"
onClick={handleConnect}
size="large"
>
{connected && mangoAccountLoading ? (
<Loading />
) : (
<div className="flex items-center justify-center">
<WalletIcon className="mr-2 h-5 w-5" />
{t('onboarding:connect-wallet')}
{walletsToDisplay !== 'all' ? (
<button
className="mt-4 flex w-full items-center justify-center text-base text-th-fgd-3 hover:text-th-fgd-1"
onClick={() => setWalletstoDisplay('all')}
>
<div>More</div>
<div>
<ChevronDownIcon className={`h-5 w-5 flex-shrink-0`} />
</div>
)}
</Button>
</button>
) : null}
</div>
) : null}
</UserSetupTransition>

View File

@ -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 (
<div className="flex flex-col items-center">
<WalletIcon className="mb-2 h-6 w-6 text-th-fgd-4" />
<p className="mb-4">{text}</p>
<Button onClick={handleConnect} disabled={!groupLoaded}>
<Button onClick={connect}>
<div className="flex items-center">
<LinkIcon className="mr-2 h-5 w-5" />
{t('connect')}

View File

@ -42,7 +42,6 @@ import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
import MaxSwapAmount from './MaxSwapAmount'
import PercentageSelectButtons from './PercentageSelectButtons'
import useIpAddress from 'hooks/useIpAddress'
import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider'
import SwapSettings from './SwapSettings'
import InlineNotification from '@components/shared/InlineNotification'
import useUnownedAccount from 'hooks/useUnownedAccount'
@ -601,9 +600,8 @@ const SwapFormSubmitButton = ({
useMargin: boolean
}) => {
const { t } = useTranslation('common')
const { connected } = useWallet()
const { connected, connect } = useWallet()
const { amount: tokenMax, amountWithBorrow } = useTokenMax(useMargin)
const { handleConnect } = useEnhancedWallet()
const showInsufficientBalance = useMargin
? amountWithBorrow.lt(amountIn)
@ -616,7 +614,7 @@ const SwapFormSubmitButton = ({
!amountOut ||
!selectedRoute)
const onClick = connected ? () => setShowConfirm(true) : handleConnect
const onClick = connected ? () => setShowConfirm(true) : connect
return (
<>

View File

@ -55,7 +55,6 @@ import MaxSizeButton from './MaxSizeButton'
import { INITIAL_SOUND_SETTINGS } from '@components/settings/SoundSettings'
import { Howl } from 'howler'
import { useWallet } from '@solana/wallet-adapter-react'
import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider'
import { isMangoError } from 'types'
import InlineNotification from '@components/shared/InlineNotification'
import SpotMarketOrderSwapForm from './SpotMarketOrderSwapForm'
@ -92,8 +91,7 @@ const AdvancedTradeForm = () => {
SOUND_SETTINGS_KEY,
INITIAL_SOUND_SETTINGS
)
const { connected } = useWallet()
const { handleConnect } = useEnhancedWallet()
const { connected, connect } = useWallet()
const {
selectedMarket,
price: oraclePrice,
@ -478,7 +476,7 @@ const AdvancedTradeForm = () => {
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
connected ? handlePlaceOrder() : handleConnect()
connected ? handlePlaceOrder() : connect()
}
const disabled =

View File

@ -24,7 +24,6 @@ import {
fetchJupiterTransaction,
} from '@blockworks-foundation/mango-v4'
import Decimal from 'decimal.js'
import { useEnhancedWallet } from '@components/wallet/EnhancedWalletProvider'
import { notify } from 'utils/notifications'
import * as sentry from '@sentry/nextjs'
import { isMangoError } from 'types'
@ -54,8 +53,7 @@ export default function SpotMarketOrderSwapForm() {
const { isUnownedAccount } = useUnownedAccount()
const [placingOrder, setPlacingOrder] = useState(false)
const { ipAllowed, ipCountry } = useIpAddress()
const { connected, publicKey } = useWallet()
const { handleConnect } = useEnhancedWallet()
const { connected, publicKey, connect } = useWallet()
const [swapFormSizeUi] = useLocalStorageState(SIZE_INPUT_UI_KEY, 'slider')
const {
selectedMarket,
@ -240,7 +238,7 @@ export default function SpotMarketOrderSwapForm() {
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
connected ? handlePlaceOrder() : handleConnect()
connected ? handlePlaceOrder() : connect()
}
const maintProjectedHealth = useMemo(() => {

View File

@ -1,64 +1,99 @@
import React, { useMemo } from 'react'
import React, { Fragment } from 'react'
import { useWallet } from '@solana/wallet-adapter-react'
import { useTranslation } from 'next-i18next'
import WalletSelect from './WalletSelect'
import WalletIcon from '@components/icons/WalletIcon'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { IS_ONBOARDED_KEY } from 'utils/constants'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { Popover, Transition } from '@headlessui/react'
import Loading from '@components/shared/Loading'
import mangoStore from '@store/mangoStore'
import Loading from '../shared/Loading'
import { useEnhancedWallet } from './EnhancedWalletProvider'
export const ConnectWalletButton: React.FC = () => {
const { connecting, wallet } = useWallet()
const { displayedWallets, handleConnect, preselectedWalletName } =
useEnhancedWallet()
const groupLoaded = mangoStore((s) => s.groupLoaded)
export default function ConnectWalletButton({
handleShowSetup,
}: {
handleShowSetup: () => void
}) {
const { t } = useTranslation('common')
const selectedWallet = useMemo(() => {
if (!displayedWallets.length || !preselectedWalletName) return undefined
return displayedWallets.find(
(w) => w.adapter.name === preselectedWalletName
)
}, [displayedWallets, preselectedWalletName])
const { wallet, wallets, select } = useWallet()
const [isOnboarded] = useLocalStorageState(IS_ONBOARDED_KEY)
const mangoAccountLoading = mangoStore((s) => s.mangoAccount.initialLoad)
return (
<div className="flex">
<button
onClick={handleConnect}
disabled={!groupLoaded}
className="relative flex h-16 bg-th-bkg-3 py-2 text-white before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-th-bkg-4 before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100 focus-visible:bg-th-bkg-4 disabled:cursor-wait disabled:opacity-25"
>
<div className="relative z-10 flex h-full items-center justify-center space-x-3 px-4">
{connecting ? (
<Loading className="h-[28px] w-[28px]" />
) : (
<div
className={`flex h-[28px] w-[28px] items-center justify-center rounded-full ${
wallet?.adapter.name === 'Solflare' ? 'bg-black' : ''
}`}
>
<img
src={wallet?.adapter.icon || selectedWallet?.adapter.icon}
className={
wallet?.adapter.name === 'Solflare'
? 'h-auto w-[20px]'
: 'h-auto w-[28px]'
}
alt={`${wallet?.adapter.name} icon`}
/>
</div>
<>
{isOnboarded ? (
<Popover>
{({ open }) => (
<>
<div className="flex">
<Popover.Button
className={`rounded-none bg-th-bkg-3 text-th-fgd-1 hover:text-white focus:outline-none focus-visible:bg-th-bkg-4`}
>
<div className="relative flex h-16 font-display before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-th-bkg-4 before:to-transparent before:opacity-0 hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100 focus-visible:bg-th-bkg-4 disabled:cursor-wait disabled:opacity-25">
<div className="mx-6 my-4 flex items-center">
<div className="relative z-10 flex h-full items-center justify-center">
<div className="relative z-10 flex items-center justify-center">
{wallet?.adapter.name && mangoAccountLoading ? (
<Loading className="mr-2 h-6 w-6" />
) : (
<WalletIcon className="mr-2 h-6 w-6" />
)}
{t('connect')}
</div>
</div>
<ChevronDownIcon
className={`ml-2 h-6 w-6 flex-shrink-0 ${
open ? 'rotate-180' : 'rotate-360'
}`}
/>
</div>
</div>
</Popover.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-in duration-200"
enterFrom="opacity-0 scale-75"
enterTo="opacity-100 scale-100"
leave="transition ease-out duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Panel className="absolute top-16 right-0 z-20 w-48 rounded-md rounded-t-none bg-th-bkg-2 px-4 py-2.5 outline-none">
{wallets.map((wallet, index) => (
<button
className="flex w-full flex-row items-center justify-between rounded-none py-2 font-normal focus:outline-none focus-visible:text-th-active md:hover:cursor-pointer md:hover:text-th-active"
onClick={() => {
select(wallet.adapter.name)
}}
key={wallet.adapter.name + index}
>
<div className="flex items-center">
<img
src={wallet.adapter.icon}
className="mr-2.5 h-5 w-5"
alt={`${wallet.adapter.name} icon`}
/>
{wallet.adapter.name}
</div>
</button>
))}
</Popover.Panel>
</Transition>
</>
)}
<div className="text-left">
<div className="mb-1.5 flex font-display text-sm leading-none text-th-fgd-1">
{t('connect')}
</div>
<div className="text-xxs font-normal leading-3 text-th-fgd-3">
{preselectedWalletName}
</div>
</Popover>
) : (
<button
className="relative h-16 rounded-none bg-th-bkg-3 bg-gradient-to-bl px-6 font-display text-base text-th-fgd-1 before:absolute before:inset-0 before:bg-gradient-to-r before:from-transparent before:via-th-bkg-4 before:to-transparent before:opacity-0 hover:cursor-pointer hover:overflow-hidden hover:before:-translate-x-full hover:before:animate-[shimmer_0.75s_normal] hover:before:opacity-100"
onClick={handleShowSetup}
>
<div className="relative z-10 flex items-center justify-center">
<WalletIcon className="mr-2 h-5 w-5 flex-shrink-0" />
{t('connect')}
</div>
</div>
</button>
<WalletSelect />
</div>
</button>
)}
</>
)
}

View File

@ -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 (
<>

View File

@ -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<void>
}
const EnhancedWalletContext = createContext<EnhancedWalletContextState>(
{} 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<string>('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 (
<EnhancedWalletContext.Provider
value={{
displayedWallets,
preselectedWalletName,
handleSelect,
handleConnect,
}}
>
{children}
</EnhancedWalletContext.Provider>
)
}

View File

@ -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 (
<Popover>
{({ open }) => (
<>
<Popover.Button
className={`flex h-16 w-10 cursor-pointer items-center justify-center rounded-none border-l border-th-bkg-4 bg-th-bkg-3 text-th-fgd-3 hover:brightness-[1.1] focus:outline-none focus-visible:bg-th-bkg-4 disabled:opacity-25`}
disabled={!group}
>
<ChevronDownIcon
className={`h-6 w-6 ${open ? 'rotate-180' : 'rotate-360'}`}
/>
</Popover.Button>
<Transition
as={Fragment}
enter="transition ease-in duration-200"
enterFrom="opacity-0 scale-75"
enterTo="opacity-100 scale-100"
leave="transition ease-out duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Panel className="absolute top-16 right-0 z-20 w-44 rounded-md rounded-t-none bg-th-bkg-2 px-4 py-2.5 outline-none">
{displayedWallets?.map((wallet, index) => (
<button
className="flex w-full flex-row items-center justify-between rounded-none py-1.5 font-normal focus:outline-none focus-visible:text-th-active md:hover:cursor-pointer md:hover:text-th-active"
onClick={() => {
handleSelect(wallet.adapter.name)
}}
key={wallet.adapter.name + index}
>
<div className="flex items-center">
<img
src={wallet.adapter.icon}
className="mr-2 h-5 w-5"
alt={`${wallet.adapter.name} icon`}
/>
{wallet.adapter.name}
</div>
</button>
))}
</Popover.Panel>
</Transition>
</>
)}
</Popover>
)
}
export default WalletSelect

View File

@ -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) {
<MangoProvider />
<QueryClientProvider client={queryClient}>
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} onError={onError}>
<EnhancedWalletProvider>
<ThemeProvider
defaultTheme="Mango Classic"
storageKey={THEME_KEY}
>
<ViewportProvider>
<PageTitle />
<Layout>
<Component {...pageProps} />
</Layout>
</ViewportProvider>
<TransactionNotification />
</ThemeProvider>
</EnhancedWalletProvider>
<WalletProvider wallets={wallets} onError={onError} autoConnect>
<ThemeProvider defaultTheme="Mango Classic" storageKey={THEME_KEY}>
<ViewportProvider>
<PageTitle />
<Layout>
<Component {...pageProps} />
</Layout>
</ViewportProvider>
<TransactionNotification />
</ThemeProvider>
</WalletProvider>
</ConnectionProvider>
</QueryClientProvider>

View File

@ -42,11 +42,9 @@ import {
RPC_PROVIDER_KEY,
} from '../utils/constants'
import {
AccountPerformanceData,
ActivityFeed,
EmptyObject,
OrderbookL2,
PerformanceDataItem,
PerpStatsItem,
PerpTradeHistory,
SerumEvent,

View File

@ -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'
}