Merges main
This commit is contained in:
commit
562d45677e
|
@ -124,13 +124,11 @@ export const DEFAULT_PUBLIC_KEY = new PublicKey(
|
|||
|
||||
export interface WalletAdapter {
|
||||
publicKey: PublicKey
|
||||
autoApprove: boolean
|
||||
connected: boolean
|
||||
signTransaction: (transaction: Transaction) => Promise<Transaction>
|
||||
signAllTransactions: (transaction: Transaction[]) => Promise<Transaction[]>
|
||||
connect: () => any
|
||||
disconnect: () => any
|
||||
on(event: string, fn: () => void): this
|
||||
}
|
||||
|
||||
export interface PerpTriggerOrder {
|
||||
|
|
|
@ -1,54 +1,113 @@
|
|||
import { Fragment, useCallback, useState } from 'react'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import React, {
|
||||
Fragment,
|
||||
useCallback,
|
||||
useState,
|
||||
useMemo,
|
||||
useEffect,
|
||||
} from 'react'
|
||||
import { Menu, Transition } from '@headlessui/react'
|
||||
import { useWallet, Wallet } from '@solana/wallet-adapter-react'
|
||||
import { WalletReadyState } from '@solana/wallet-adapter-base'
|
||||
import {
|
||||
CurrencyDollarIcon,
|
||||
DuplicateIcon,
|
||||
LogoutIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import { PROVIDER_LOCAL_STORAGE_KEY } from '../hooks/useWallet'
|
||||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
import { abbreviateAddress, copyToClipboard } from '../utils'
|
||||
import WalletSelect from './WalletSelect'
|
||||
import { WalletIcon, ProfileIcon } from './icons'
|
||||
import AccountsModal from './AccountsModal'
|
||||
import { useEffect } from 'react'
|
||||
import { notify } from 'utils/notifications'
|
||||
import { abbreviateAddress, copyToClipboard } from 'utils'
|
||||
import useMangoStore from 'stores/useMangoStore'
|
||||
import { ProfileIcon, WalletIcon } from './icons'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { DEFAULT_PROVIDER, WALLET_PROVIDERS } from '../utils/wallet-adapters'
|
||||
import { WalletSelect } from 'components/WalletSelect'
|
||||
import AccountsModal from './AccountsModal'
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
const ConnectWalletButton = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const pfp = useMangoStore((s) => s.wallet.pfp)
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const set = useMangoStore((s) => s.set)
|
||||
const [showAccountsModal, setShowAccountsModal] = useState(false)
|
||||
const [selectedWallet, setSelectedWallet] = useState(DEFAULT_PROVIDER.url)
|
||||
const [savedProviderUrl] = useLocalStorageState(
|
||||
PROVIDER_LOCAL_STORAGE_KEY,
|
||||
DEFAULT_PROVIDER.url
|
||||
)
|
||||
|
||||
// update in useEffect to prevent SRR error from next.js
|
||||
useEffect(() => {
|
||||
setSelectedWallet(savedProviderUrl)
|
||||
}, [savedProviderUrl])
|
||||
|
||||
const handleWalletConect = () => {
|
||||
wallet.connect()
|
||||
set((state) => {
|
||||
state.selectedMangoAccount.initialLoad = true
|
||||
export const handleWalletConnect = (wallet: Wallet) => {
|
||||
if (!wallet) {
|
||||
return
|
||||
}
|
||||
if (wallet.readyState === WalletReadyState.NotDetected) {
|
||||
window.open(wallet.adapter.url, '_blank')
|
||||
} else {
|
||||
wallet?.adapter?.connect().catch((e) => {
|
||||
if (e.name.includes('WalletLoadError')) {
|
||||
notify({
|
||||
title: `${wallet.adapter.name} Error`,
|
||||
type: 'error',
|
||||
description: `Please install ${wallet.adapter.name} and then reload this page.`,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const ConnectWalletButton: React.FC = () => {
|
||||
const { connected, publicKey, wallet, wallets, select } = useWallet()
|
||||
const { t } = useTranslation('common')
|
||||
const pfp = useMangoStore((s) => s.wallet.pfp)
|
||||
const set = useMangoStore((s) => s.set)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const [showAccountsModal, setShowAccountsModal] = useState(false)
|
||||
|
||||
const defaultWallets = useMemo(() => {
|
||||
return ['Phantom', 'Solflare', 'Sollet']
|
||||
}, [])
|
||||
|
||||
const installedWallets = useMemo(() => {
|
||||
const installed: Wallet[] = []
|
||||
|
||||
for (const wallet of wallets) {
|
||||
if (wallet.readyState === WalletReadyState.Installed) {
|
||||
installed.push(wallet)
|
||||
}
|
||||
}
|
||||
|
||||
return installed
|
||||
}, [wallets])
|
||||
|
||||
const displayedWallets = useMemo(() => {
|
||||
return uniqBy(
|
||||
[
|
||||
...installedWallets,
|
||||
...wallets.filter((w) => defaultWallets.includes(w.adapter.name)),
|
||||
],
|
||||
(w) => {
|
||||
return w.adapter.name
|
||||
}
|
||||
)
|
||||
}, [wallets, installedWallets, defaultWallets])
|
||||
|
||||
const handleConnect = useCallback(() => {
|
||||
handleWalletConnect(wallet)
|
||||
}, [wallet])
|
||||
|
||||
const handleCloseAccounts = useCallback(() => {
|
||||
setShowAccountsModal(false)
|
||||
}, [])
|
||||
|
||||
const handleDisconnect = useCallback(() => {
|
||||
wallet?.adapter?.disconnect()
|
||||
set((state) => {
|
||||
state.wallet.connected = false
|
||||
state.mangoAccounts = []
|
||||
state.selectedMangoAccount.current = null
|
||||
state.tradeHistory = { spot: [], perp: [] }
|
||||
})
|
||||
notify({
|
||||
type: 'info',
|
||||
title: t('wallet-disconnected'),
|
||||
})
|
||||
}, [wallet, set, t])
|
||||
|
||||
useEffect(() => {
|
||||
if (!wallet && displayedWallets?.length) {
|
||||
select(displayedWallets[0].adapter.name)
|
||||
}
|
||||
}, [wallet, displayedWallets, select])
|
||||
|
||||
return (
|
||||
<>
|
||||
{connected && wallet?.publicKey ? (
|
||||
{connected && publicKey ? (
|
||||
<Menu>
|
||||
{({ open }) => (
|
||||
<div className="relative" id="profile-menu-tip">
|
||||
|
@ -83,7 +142,7 @@ const ConnectWalletButton = () => {
|
|||
<Menu.Item>
|
||||
<button
|
||||
className="flex w-full flex-row items-center rounded-none py-0.5 font-normal hover:cursor-pointer hover:text-th-primary focus:outline-none"
|
||||
onClick={() => copyToClipboard(wallet?.publicKey)}
|
||||
onClick={() => copyToClipboard(publicKey)}
|
||||
>
|
||||
<DuplicateIcon className="h-4 w-4" />
|
||||
<div className="pl-2 text-left">{t('copy-address')}</div>
|
||||
|
@ -92,13 +151,13 @@ const ConnectWalletButton = () => {
|
|||
<Menu.Item>
|
||||
<button
|
||||
className="flex w-full flex-row items-center rounded-none py-0.5 font-normal hover:cursor-pointer hover:text-th-primary focus:outline-none"
|
||||
onClick={() => wallet.disconnect()}
|
||||
onClick={handleDisconnect}
|
||||
>
|
||||
<LogoutIcon className="h-4 w-4" />
|
||||
<div className="pl-2 text-left">
|
||||
<div className="pb-0.5">{t('disconnect')}</div>
|
||||
<div className="text-xs text-th-fgd-4">
|
||||
{abbreviateAddress(wallet?.publicKey)}
|
||||
{abbreviateAddress(publicKey)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
@ -114,8 +173,8 @@ const ConnectWalletButton = () => {
|
|||
id="connect-wallet-tip"
|
||||
>
|
||||
<button
|
||||
onClick={handleWalletConect}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
onClick={handleConnect}
|
||||
disabled={!mangoGroup}
|
||||
className="rounded-none bg-th-primary-dark text-th-bkg-1 hover:brightness-[1.1] focus:outline-none disabled:cursor-wait disabled:text-th-bkg-2"
|
||||
>
|
||||
<div className="default-transition flex h-full flex-row items-center justify-center px-3">
|
||||
|
@ -124,25 +183,25 @@ const ConnectWalletButton = () => {
|
|||
<div className="mb-0.5 whitespace-nowrap font-bold">
|
||||
{t('connect')}
|
||||
</div>
|
||||
<div className="text-xxs font-normal leading-3 tracking-wider text-th-bkg-2">
|
||||
{WALLET_PROVIDERS.find((p) => p.url === selectedWallet)?.name}
|
||||
</div>
|
||||
{wallet?.adapter?.name && (
|
||||
<div className="text-xxs font-normal leading-3 tracking-wider text-th-bkg-2">
|
||||
{wallet.adapter.name}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<div className="relative">
|
||||
<WalletSelect />
|
||||
<WalletSelect wallets={displayedWallets} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{showAccountsModal ? (
|
||||
{showAccountsModal && (
|
||||
<AccountsModal
|
||||
onClose={handleCloseAccounts}
|
||||
isOpen={showAccountsModal}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ConnectWalletButton
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { FunctionComponent, ReactNode } from 'react'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import Button from './Button'
|
||||
|
||||
interface EmptyStateProps {
|
||||
|
@ -8,6 +7,7 @@ interface EmptyStateProps {
|
|||
onClickButton?: () => void
|
||||
desc?: string
|
||||
title: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const EmptyState: FunctionComponent<EmptyStateProps> = ({
|
||||
|
@ -16,10 +16,8 @@ const EmptyState: FunctionComponent<EmptyStateProps> = ({
|
|||
onClickButton,
|
||||
desc,
|
||||
title,
|
||||
disabled = false,
|
||||
}) => {
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center rounded-lg px-4 pb-2 text-th-fgd-1">
|
||||
<div className="mb-1 h-6 w-6 text-th-primary">{icon}</div>
|
||||
|
@ -34,11 +32,7 @@ const EmptyState: FunctionComponent<EmptyStateProps> = ({
|
|||
</p>
|
||||
) : null}
|
||||
{buttonText && onClickButton ? (
|
||||
<Button
|
||||
className="mt-2"
|
||||
onClick={onClickButton}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
>
|
||||
<Button className="mt-2" onClick={onClickButton} disabled={disabled}>
|
||||
{buttonText}
|
||||
</Button>
|
||||
) : null}
|
||||
|
|
|
@ -1,31 +1,11 @@
|
|||
import React, { FunctionComponent } from 'react'
|
||||
// import styled from '@emotion/styled'
|
||||
import React, { FunctionComponent, useCallback } from 'react'
|
||||
import { LinkIcon } from '@heroicons/react/outline'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { MoveIcon } from './icons'
|
||||
import EmptyState from './EmptyState'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
// const StyledDragWrapperContent = styled.div`
|
||||
// transition: all 0.25s ease-in;
|
||||
// opacity: 0;
|
||||
// `
|
||||
|
||||
// const StyledDragBkg = styled.div`
|
||||
// transition: all 0.25s ease-in;
|
||||
// opacity: 0;
|
||||
// `
|
||||
|
||||
// const StyledDragWrapper = styled.div`
|
||||
// :hover {
|
||||
// ${StyledDragWrapperContent} {
|
||||
// opacity: 1;
|
||||
// }
|
||||
// ${StyledDragBkg} {
|
||||
// opacity: 0.9;
|
||||
// }
|
||||
// }
|
||||
// `
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { handleWalletConnect } from 'components/ConnectWalletButton'
|
||||
|
||||
interface FloatingElementProps {
|
||||
className?: string
|
||||
|
@ -38,9 +18,15 @@ const FloatingElement: FunctionComponent<FloatingElementProps> = ({
|
|||
showConnect,
|
||||
}) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { wallet } = useWallet()
|
||||
const { uiLocked } = useMangoStore((s) => s.settings)
|
||||
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
|
||||
const handleConnect = useCallback(() => {
|
||||
handleWalletConnect(wallet)
|
||||
}, [wallet])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`thin-scroll relative overflow-auto overflow-x-hidden rounded-lg bg-th-bkg-2 p-2.5 md:p-4 ${className}`}
|
||||
|
@ -49,9 +35,10 @@ const FloatingElement: FunctionComponent<FloatingElementProps> = ({
|
|||
<div className="absolute top-0 left-0 z-10 h-full w-full">
|
||||
<div className="relative z-10 flex h-full flex-col items-center justify-center">
|
||||
<EmptyState
|
||||
disabled={!wallet || !mangoGroup}
|
||||
buttonText={t('connect')}
|
||||
icon={<LinkIcon />}
|
||||
onClickButton={() => (wallet ? wallet.connect() : null)}
|
||||
onClickButton={handleConnect}
|
||||
title={t('connect-wallet')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,6 @@ import useMangoStore from '../stores/useMangoStore'
|
|||
import {
|
||||
connectionSelector,
|
||||
walletConnectedSelector,
|
||||
walletSelector,
|
||||
} from '../stores/selectors'
|
||||
import { sortBy, sum } from 'lodash'
|
||||
import {
|
||||
|
@ -46,6 +45,8 @@ import { numberFormatter } from './SwapTokenInfo'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import Tabs from './Tabs'
|
||||
import SwapTokenInsights from './SwapTokenInsights'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { handleWalletConnect } from 'components/ConnectWalletButton'
|
||||
|
||||
const TABS = ['Market Data', 'Performance Insights']
|
||||
|
||||
|
@ -53,10 +54,9 @@ type UseJupiterProps = Parameters<typeof useJupiter>[0]
|
|||
|
||||
const JupiterForm: FunctionComponent = () => {
|
||||
const { t } = useTranslation(['common', 'swap'])
|
||||
const wallet = useMangoStore(walletSelector)
|
||||
const connection = useMangoStore(connectionSelector)
|
||||
const connected = useMangoStore(walletConnectedSelector)
|
||||
|
||||
const { wallet, publicKey } = useWallet()
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [depositAndFee, setDepositAndFee] = useState(null)
|
||||
const [selectedRoute, setSelectedRoute] = useState<RouteInfo>(null)
|
||||
|
@ -93,7 +93,7 @@ const JupiterForm: FunctionComponent = () => {
|
|||
const ownedTokens = []
|
||||
const ownedTokenAccounts = await getTokenAccountsByOwnerWithWrappedSol(
|
||||
connection,
|
||||
wallet.publicKey
|
||||
publicKey
|
||||
)
|
||||
|
||||
ownedTokenAccounts.forEach((account) => {
|
||||
|
@ -237,6 +237,10 @@ const JupiterForm: FunctionComponent = () => {
|
|||
}
|
||||
}, [routeMap, tokens, formValue.inputMint])
|
||||
|
||||
const handleConnect = useCallback(() => {
|
||||
handleWalletConnect(wallet)
|
||||
}, [wallet])
|
||||
|
||||
const inputWalletBalance = () => {
|
||||
if (walletTokens.length) {
|
||||
const walletToken = walletTokens.filter((t) => {
|
||||
|
@ -373,11 +377,11 @@ const JupiterForm: FunctionComponent = () => {
|
|||
</div>
|
||||
<a
|
||||
className="flex items-center text-xs text-th-fgd-3 hover:text-th-fgd-2"
|
||||
href={`https://explorer.solana.com/address/${wallet?.publicKey}`}
|
||||
href={`https://explorer.solana.com/address/${publicKey}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{abbreviateAddress(wallet.publicKey)}
|
||||
{abbreviateAddress(publicKey)}
|
||||
<ExternalLinkIcon className="ml-0.5 -mt-0.5 h-3.5 w-3.5" />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -945,8 +949,8 @@ const JupiterForm: FunctionComponent = () => {
|
|||
<Button
|
||||
disabled={swapDisabled}
|
||||
onClick={async () => {
|
||||
if (!connected && zeroKey !== wallet?.publicKey) {
|
||||
wallet.connect()
|
||||
if (!connected && zeroKey !== publicKey) {
|
||||
handleConnect()
|
||||
} else if (!loading && selectedRoute && connected) {
|
||||
setSwapping(true)
|
||||
let txCount = 1
|
||||
|
|
|
@ -5,7 +5,7 @@ import useLocalStorageState from '../hooks/useLocalStorageState'
|
|||
import MenuItem from './MenuItem'
|
||||
import ThemeSwitch from './ThemeSwitch'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import ConnectWalletButton from './ConnectWalletButton'
|
||||
import { ConnectWalletButton } from 'components'
|
||||
import NavDropMenu from './NavDropMenu'
|
||||
import AccountsModal from './AccountsModal'
|
||||
import LanguageSwitch from './LanguageSwitch'
|
||||
|
@ -16,23 +16,6 @@ import TradeNavMenu from './TradeNavMenu'
|
|||
import { CalculatorIcon, LightBulbIcon } from '@heroicons/react/outline'
|
||||
import { MangoIcon } from './icons'
|
||||
|
||||
// const StyledNewLabel = ({ children, ...props }) => (
|
||||
// <div style={{ fontSize: '0.5rem', marginLeft: '1px' }} {...props}>
|
||||
// {children}
|
||||
// </div>
|
||||
// )
|
||||
|
||||
// <div className="relative">
|
||||
// <MenuItem href="/referral">
|
||||
// {t('referrals')}
|
||||
// <div className="absolute flex items-center justify-center h-4 px-1.5 bg-gradient-to-br from-red-500 to-yellow-500 rounded-full -right-3 -top-3">
|
||||
// <StyledNewLabel className="text-white uppercase">
|
||||
// new
|
||||
// </StyledNewLabel>
|
||||
// </div>
|
||||
// </MenuItem>
|
||||
// </div>
|
||||
|
||||
const TopBar = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
import React, { useEffect, useMemo } from 'react'
|
||||
import {
|
||||
ConnectionProvider,
|
||||
useWallet,
|
||||
WalletProvider as SolanaWalletProvider,
|
||||
} from '@solana/wallet-adapter-react'
|
||||
import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'
|
||||
import { getWalletAdapters } from '@solana/wallet-adapter-wallets'
|
||||
import { clusterApiUrl } from '@solana/web3.js'
|
||||
|
||||
import useMangoStore from 'stores/useMangoStore'
|
||||
|
||||
const WalletListener: React.FC = () => {
|
||||
const set = useMangoStore((s) => s.set)
|
||||
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
|
||||
const {
|
||||
publicKey,
|
||||
wallet,
|
||||
signTransaction,
|
||||
signAllTransactions,
|
||||
connect,
|
||||
disconnect,
|
||||
connected,
|
||||
} = useWallet()
|
||||
|
||||
const connecting = wallet?.adapter?.connecting
|
||||
|
||||
useEffect(() => {
|
||||
const onConnect = async () => {
|
||||
set((state) => {
|
||||
state.selectedMangoAccount.initialLoad = true
|
||||
state.wallet.providerUrl = wallet.adapter.url
|
||||
state.wallet.connected = true
|
||||
state.wallet.current = {
|
||||
publicKey,
|
||||
connected: true,
|
||||
signTransaction,
|
||||
signAllTransactions,
|
||||
connect,
|
||||
disconnect,
|
||||
}
|
||||
})
|
||||
|
||||
await actions.fetchAllMangoAccounts()
|
||||
|
||||
actions.fetchProfilePicture()
|
||||
actions.reloadOrders()
|
||||
actions.fetchTradeHistory()
|
||||
actions.fetchWalletTokens()
|
||||
}
|
||||
|
||||
if (connecting) {
|
||||
onConnect()
|
||||
}
|
||||
}, [
|
||||
connecting,
|
||||
connected,
|
||||
set,
|
||||
actions,
|
||||
wallet,
|
||||
publicKey,
|
||||
signAllTransactions,
|
||||
signTransaction,
|
||||
connect,
|
||||
disconnect,
|
||||
])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export const WalletProvider: React.FC = ({ children }) => {
|
||||
// The network can be set to 'devnet', 'testnet', or 'mainnet-beta'.
|
||||
const network = WalletAdapterNetwork.Mainnet
|
||||
|
||||
// You can also provide a custom RPC endpoint.
|
||||
const endpoint = useMemo(() => clusterApiUrl(network), [network])
|
||||
|
||||
// @solana/wallet-adapter-wallets includes all the adapters but supports tree shaking and lazy loading --
|
||||
// Only the wallets you configure here will be compiled into your application, and only the dependencies
|
||||
// of wallets that your users connect to will be loaded.
|
||||
const wallets = getWalletAdapters({ network })
|
||||
|
||||
return (
|
||||
<ConnectionProvider endpoint={endpoint}>
|
||||
<SolanaWalletProvider wallets={wallets}>
|
||||
<WalletListener />
|
||||
{children}
|
||||
</SolanaWalletProvider>
|
||||
</ConnectionProvider>
|
||||
)
|
||||
}
|
|
@ -1,16 +1,13 @@
|
|||
import { Fragment } from 'react'
|
||||
import React, { Fragment } from 'react'
|
||||
import { Menu, Transition } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/solid'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { WALLET_PROVIDERS } from '../utils/wallet-adapters'
|
||||
import { useWallet, Wallet } from '@solana/wallet-adapter-react'
|
||||
|
||||
export default function WalletSelect() {
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
export const WalletSelect: React.FC<{ wallets: Wallet[] }> = ({ wallets }) => {
|
||||
const { select } = useWallet()
|
||||
|
||||
const handleSelectProvider = (url) => {
|
||||
setMangoStore((state) => {
|
||||
state.wallet.providerUrl = url
|
||||
})
|
||||
if (!wallets?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -38,15 +35,21 @@ export default function WalletSelect() {
|
|||
leaveTo="opacity-0"
|
||||
>
|
||||
<Menu.Items className="absolute right-0 z-20 w-44 rounded-b-md bg-th-bkg-3 px-4 py-2.5 outline-none">
|
||||
{WALLET_PROVIDERS.map(({ name, url, icon }) => (
|
||||
<Menu.Item key={name}>
|
||||
{wallets?.map((wallet, index) => (
|
||||
<Menu.Item key={index}>
|
||||
<button
|
||||
className="flex w-full flex-row items-center justify-between rounded-none py-1.5 font-normal hover:cursor-pointer hover:text-th-primary focus:outline-none"
|
||||
onClick={() => handleSelectProvider(url)}
|
||||
onClick={() => {
|
||||
select(wallet.adapter.name)
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<img src={icon} className="mr-2 h-4 w-4" />
|
||||
{name}
|
||||
<img
|
||||
src={wallet.adapter.icon}
|
||||
className="mr-2 h-4 w-4"
|
||||
alt={`${wallet.adapter.name} icon`}
|
||||
/>
|
||||
{wallet.adapter.name}
|
||||
</div>
|
||||
</button>
|
||||
</Menu.Item>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
export * from './AccountInfo'
|
||||
export * from './AccountNameModal'
|
||||
export * from './AccountSelect'
|
||||
export * from './AccountsModal'
|
||||
export * from './AlphaModal'
|
||||
export * from './BalancesTable'
|
||||
export * from './Button'
|
||||
export * from './ButtonGroup'
|
||||
export * from './Chart'
|
||||
export * from './Checkbox'
|
||||
export * from './CloseAccountModal'
|
||||
export * from './ConnectWalletButton'
|
||||
export * from './CreateAlertModal'
|
||||
export * from './DayHighLow'
|
||||
export * from './DelegateModal'
|
||||
export * from './DepositModal'
|
||||
export * from './DepositMsrmModal'
|
||||
export * from './DropMenu'
|
||||
export * from './EmptyState'
|
||||
export * from './ErrorBoundary'
|
||||
export * from './FavoritesShortcutBar'
|
||||
export * from './FeeDiscountsTable'
|
||||
export * from './FlipCard'
|
||||
export * from './FloatingElement'
|
||||
export * from './GlobalNotification'
|
||||
export * from './icons'
|
||||
export * from './ImageWithFallback'
|
||||
export * from './InlineNotification'
|
||||
export * from './Input'
|
||||
export * from './IntroTips'
|
||||
export * from './JupiterForm'
|
||||
export * from './LanguageSwitch'
|
||||
export * from './LeverageSlider'
|
||||
export * from './Loading'
|
||||
export * from './MangoAccountSelect'
|
||||
export * from './MangoIcon'
|
||||
export * from './ManualRefresh'
|
||||
export * from './MarketBalances'
|
||||
export * from './MarketCloseModal'
|
||||
export * from './MarketDetails'
|
||||
export * from './MarketFee'
|
||||
export * from './MarketMenuItem'
|
||||
export * from './MarketNavItem'
|
||||
export * from './MarketSelect'
|
||||
export * from './MarketsModal'
|
||||
export * from './MenuItem'
|
||||
export * from './Modal'
|
||||
export * from './NavDropMenu'
|
||||
export * from './NewAccount'
|
||||
export * from './Notification'
|
||||
export * from './OpenOrdersTable'
|
||||
export * from './Orderbook'
|
||||
export * from './PageBodyContainer'
|
||||
export * from './Pagination'
|
||||
export * from './PerpPositionsTable'
|
||||
export * from './PerpSideBadge'
|
||||
export * from './PnlText'
|
||||
export * from './RecentMarketTrades'
|
||||
export * from './ResetLayout'
|
||||
export * from './Select'
|
||||
export * from './Settings'
|
||||
export * from './SettingsModal'
|
||||
export * from './SideBadge'
|
||||
export * from './Slider'
|
||||
export * from './styles'
|
||||
export * from './SwapSettingsModal'
|
||||
export * from './SwapTokenInfo'
|
||||
export * from './SwapTokenInsights'
|
||||
export * from './SwapTokenSelect'
|
||||
export * from './Switch'
|
||||
export * from './SwitchMarketDropdown'
|
||||
export * from './TableElements'
|
||||
export * from './Tabs'
|
||||
export * from './ThemeSwitch'
|
||||
export * from './Tooltip'
|
||||
export * from './TopBar'
|
||||
export * from './TradeHistoryTable'
|
||||
export * from './TradeNavMenu'
|
||||
export * from './TradePageGrid'
|
||||
export * from './UiLock'
|
||||
export * from './UserInfo'
|
||||
export * from './UserMarketInfo'
|
||||
export * from './WalletProvider'
|
||||
export * from './WithdrawModal'
|
||||
export * from './WithdrawMsrmModal'
|
|
@ -174,6 +174,7 @@ export default function StatsPerps({ perpStats }) {
|
|||
x.toLocaleString(undefined, { maximumFractionDigits: 4 })
|
||||
}
|
||||
type="area"
|
||||
yAxisWidth={70}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
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 { WalletAdapter } from '../@types/types'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { DEFAULT_PROVIDER, WALLET_PROVIDERS } from '../utils/wallet-adapters'
|
||||
|
||||
export const PROVIDER_LOCAL_STORAGE_KEY = 'walletProvider-0.1'
|
||||
|
||||
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 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.fetchProfilePicture()
|
||||
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 = { spot: [], perp: [] }
|
||||
})
|
||||
notify({
|
||||
type: 'info',
|
||||
title: t('wallet-disconnected'),
|
||||
})
|
||||
})
|
||||
}, [wallet, setMangoStore])
|
||||
|
||||
return { connected, wallet }
|
||||
}
|
|
@ -17,13 +17,16 @@
|
|||
"test-all": "yarn lint && yarn type-check && yarn test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-client": "^3.3.20",
|
||||
"@blockworks-foundation/mango-client": "^3.3.21",
|
||||
"@headlessui/react": "^1.2.0",
|
||||
"@heroicons/react": "^1.0.0",
|
||||
"@jup-ag/react-hook": "^1.0.0-beta.16",
|
||||
"@project-serum/serum": "0.13.55",
|
||||
"@project-serum/sol-wallet-adapter": "0.2.0",
|
||||
"@solana/web3.js": "^1.31.0",
|
||||
"@solana/wallet-adapter-base": "^0.9.5",
|
||||
"@solana/wallet-adapter-react": "^0.15.4",
|
||||
"@solana/wallet-adapter-wallets": "^0.15.5",
|
||||
"@solana/web3.js": "^1.36.0",
|
||||
"@solflare-wallet/pfp": "^0.0.6",
|
||||
"@solflare-wallet/sdk": "^1.0.10",
|
||||
"@tippyjs/react": "^4.2.5",
|
||||
|
|
|
@ -4,7 +4,6 @@ import '../node_modules/react-grid-layout/css/styles.css'
|
|||
import '../node_modules/react-resizable/css/styles.css'
|
||||
import 'intro.js/introjs.css'
|
||||
import '../styles/index.css'
|
||||
import useWallet from '../hooks/useWallet'
|
||||
import useHydrateStore from '../hooks/useHydrateStore'
|
||||
import Notifications from '../components/Notification'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
|
@ -25,17 +24,13 @@ import {
|
|||
ReferrerIdRecordLayout,
|
||||
ReferrerIdRecord,
|
||||
} from '@blockworks-foundation/mango-client'
|
||||
import { WalletProvider } from 'components'
|
||||
|
||||
const MangoStoreUpdater = () => {
|
||||
useHydrateStore()
|
||||
return null
|
||||
}
|
||||
|
||||
const WalletStoreUpdater = () => {
|
||||
useWallet()
|
||||
return null
|
||||
}
|
||||
|
||||
const OpenOrdersStoreUpdater = () => {
|
||||
useOpenOrders()
|
||||
return null
|
||||
|
@ -153,28 +148,29 @@ function App({ Component, pageProps }) {
|
|||
<ErrorBoundary>
|
||||
<PageTitle />
|
||||
<MangoStoreUpdater />
|
||||
<WalletStoreUpdater />
|
||||
<OpenOrdersStoreUpdater />
|
||||
<PerpPositionsStoreUpdater />
|
||||
<FetchReferrer />
|
||||
</ErrorBoundary>
|
||||
|
||||
<ThemeProvider defaultTheme="Mango">
|
||||
<ViewportProvider>
|
||||
<div className="min-h-screen bg-th-bkg-1">
|
||||
<ErrorBoundary>
|
||||
<GlobalNotification />
|
||||
<Component {...pageProps} />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<div className="fixed bottom-0 left-0 z-20 w-full md:hidden">
|
||||
<ErrorBoundary>
|
||||
<BottomBar />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<WalletProvider>
|
||||
<ViewportProvider>
|
||||
<div className="min-h-screen bg-th-bkg-1">
|
||||
<ErrorBoundary>
|
||||
<GlobalNotification />
|
||||
<Component {...pageProps} />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
<div className="fixed bottom-0 left-0 z-20 w-full md:hidden">
|
||||
<ErrorBoundary>
|
||||
<BottomBar />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
|
||||
<Notifications />
|
||||
</ViewportProvider>
|
||||
<Notifications />
|
||||
</ViewportProvider>
|
||||
</WalletProvider>
|
||||
</ThemeProvider>
|
||||
</ErrorBoundary>
|
||||
</>
|
||||
|
|
|
@ -19,43 +19,41 @@ import {
|
|||
} from '@heroicons/react/outline'
|
||||
import { ChevronDownIcon } from '@heroicons/react/solid'
|
||||
import { nativeToUi, ZERO_BN } from '@blockworks-foundation/mango-client'
|
||||
import useMangoStore, {
|
||||
serumProgramId,
|
||||
MNGO_INDEX,
|
||||
} from '../stores/useMangoStore'
|
||||
import PageBodyContainer from '../components/PageBodyContainer'
|
||||
import TopBar from '../components/TopBar'
|
||||
import AccountOrders from '../components/account_page/AccountOrders'
|
||||
import AccountHistory from '../components/account_page/AccountHistory'
|
||||
import AccountsModal from '../components/AccountsModal'
|
||||
import AccountOverview from '../components/account_page/AccountOverview'
|
||||
import AccountInterest from '../components/account_page/AccountInterest'
|
||||
import AccountFunding from '../components/account_page/AccountFunding'
|
||||
import AccountNameModal from '../components/AccountNameModal'
|
||||
import { IconButton, LinkButton } from '../components/Button'
|
||||
import EmptyState from '../components/EmptyState'
|
||||
import Loading from '../components/Loading'
|
||||
import Swipeable from '../components/mobile/Swipeable'
|
||||
import Tabs from '../components/Tabs'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
import { breakpoints } from '../components/TradePageGrid'
|
||||
import useMangoStore, { serumProgramId, MNGO_INDEX } from 'stores/useMangoStore'
|
||||
import PageBodyContainer from 'components/PageBodyContainer'
|
||||
import TopBar from 'components/TopBar'
|
||||
import AccountOrders from 'components/account_page/AccountOrders'
|
||||
import AccountHistory from 'components/account_page/AccountHistory'
|
||||
import AccountsModal from 'components/AccountsModal'
|
||||
import AccountOverview from 'components/account_page/AccountOverview'
|
||||
import AccountInterest from 'components/account_page/AccountInterest'
|
||||
import AccountFunding from 'components/account_page/AccountFunding'
|
||||
import AccountNameModal from 'components/AccountNameModal'
|
||||
import { IconButton, LinkButton } from 'components/Button'
|
||||
import EmptyState from 'components/EmptyState'
|
||||
import Loading from 'components/Loading'
|
||||
import Swipeable from 'components/mobile/Swipeable'
|
||||
import Tabs from 'components/Tabs'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
import { breakpoints } from 'components/TradePageGrid'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Select from '../components/Select'
|
||||
import Select from 'components/Select'
|
||||
import { useRouter } from 'next/router'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import CloseAccountModal from '../components/CloseAccountModal'
|
||||
import { notify } from '../utils/notifications'
|
||||
import CloseAccountModal from 'components/CloseAccountModal'
|
||||
import { notify } from 'utils/notifications'
|
||||
import {
|
||||
actionsSelector,
|
||||
mangoAccountSelector,
|
||||
mangoGroupSelector,
|
||||
walletConnectedSelector,
|
||||
} from '../stores/selectors'
|
||||
import CreateAlertModal from '../components/CreateAlertModal'
|
||||
import { copyToClipboard } from '../utils'
|
||||
import DelegateModal from '../components/DelegateModal'
|
||||
} from 'stores/selectors'
|
||||
import CreateAlertModal from 'components/CreateAlertModal'
|
||||
import { copyToClipboard } from 'utils'
|
||||
import DelegateModal from 'components/DelegateModal'
|
||||
import { Menu, Transition } from '@headlessui/react'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { handleWalletConnect } from 'components/ConnectWalletButton'
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
|
@ -77,15 +75,12 @@ export default function Account() {
|
|||
const { t } = useTranslation(['common', 'close-account', 'delegate'])
|
||||
const { width } = useViewport()
|
||||
const router = useRouter()
|
||||
|
||||
const connected = useMangoStore(walletConnectedSelector)
|
||||
const { connected, wallet, publicKey } = useWallet()
|
||||
const isLoading = useMangoStore((s) => s.selectedMangoAccount.initialLoad)
|
||||
const mangoAccount = useMangoStore(mangoAccountSelector)
|
||||
const mangoGroup = useMangoStore(mangoGroupSelector)
|
||||
const wallet = useMangoStore((s) => s.wallet.current)
|
||||
const isLoading = useMangoStore((s) => s.selectedMangoAccount.initialLoad)
|
||||
const actions = useMangoStore(actionsSelector)
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
|
||||
const [showAccountsModal, setShowAccountsModal] = useState(false)
|
||||
const [showNameModal, setShowNameModal] = useState(false)
|
||||
const [showCloseAccountModal, setShowCloseAccountModal] = useState(false)
|
||||
|
@ -97,10 +92,11 @@ export default function Account() {
|
|||
const [viewIndex, setViewIndex] = useState(0)
|
||||
const [activeTab, setActiveTab] = useState(TABS[0])
|
||||
|
||||
const connecting = wallet?.adapter?.connecting
|
||||
const isMobile = width ? width < breakpoints.sm : false
|
||||
const { pubkey } = router.query
|
||||
const isDelegatedAccount = wallet?.publicKey
|
||||
? !mangoAccount?.owner?.equals(wallet?.publicKey)
|
||||
const isDelegatedAccount = publicKey
|
||||
? !mangoAccount?.owner?.equals(publicKey)
|
||||
: false
|
||||
|
||||
const handleCloseAlertModal = useCallback(() => {
|
||||
|
@ -123,6 +119,10 @@ export default function Account() {
|
|||
setShowDelegateModal(false)
|
||||
}, [])
|
||||
|
||||
const handleConnect = useCallback(() => {
|
||||
handleWalletConnect(wallet)
|
||||
}, [wallet])
|
||||
|
||||
useEffect(() => {
|
||||
async function loadUnownedMangoAccount() {
|
||||
try {
|
||||
|
@ -141,6 +141,7 @@ export default function Account() {
|
|||
setResetOnLeave(true)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('error', error)
|
||||
router.push('/account')
|
||||
}
|
||||
}
|
||||
|
@ -153,12 +154,6 @@ export default function Account() {
|
|||
}
|
||||
}, [pubkey, mangoGroup])
|
||||
|
||||
useEffect(() => {
|
||||
if (connected) {
|
||||
router.push('/account')
|
||||
}
|
||||
}, [connected])
|
||||
|
||||
useEffect(() => {
|
||||
const handleRouteChange = () => {
|
||||
if (resetOnLeave) {
|
||||
|
@ -205,6 +200,14 @@ export default function Account() {
|
|||
)
|
||||
}, [mangoAccount])
|
||||
|
||||
console.log('connecting', connecting)
|
||||
|
||||
useEffect(() => {
|
||||
if (connecting) {
|
||||
router.push('/account')
|
||||
}
|
||||
}, [connecting, router])
|
||||
|
||||
const handleRedeemMngo = async () => {
|
||||
const wallet = useMangoStore.getState().wallet.current
|
||||
const mangoClient = useMangoStore.getState().connection.client
|
||||
|
@ -447,14 +450,16 @@ export default function Account() {
|
|||
icon={<CurrencyDollarIcon />}
|
||||
onClickButton={() => setShowAccountsModal(true)}
|
||||
title={t('no-account-found')}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<EmptyState
|
||||
buttonText={t('connect')}
|
||||
desc={t('connect-view')}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
icon={<LinkIcon />}
|
||||
onClickButton={() => wallet.connect()}
|
||||
onClickButton={handleConnect}
|
||||
title={t('connect-wallet')}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
mangoCacheSelector,
|
||||
mangoGroupConfigSelector,
|
||||
mangoGroupSelector,
|
||||
walletSelector,
|
||||
} from '../stores/selectors'
|
||||
import Button, { IconButton } from '../components/Button'
|
||||
import {
|
||||
|
@ -41,6 +40,8 @@ import MobileTableHeader from '../components/mobile/MobileTableHeader'
|
|||
import Input, { Label } from '../components/Input'
|
||||
import InlineNotification from '../components/InlineNotification'
|
||||
import useMangoAccount from '../hooks/useMangoAccount'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { handleWalletConnect } from 'components/ConnectWalletButton'
|
||||
|
||||
export async function getStaticProps({ locale }) {
|
||||
return {
|
||||
|
@ -72,7 +73,6 @@ export default function Referral() {
|
|||
const mangoCache = useMangoStore(mangoCacheSelector)
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const groupConfig = useMangoStore(mangoGroupConfigSelector)
|
||||
const wallet = useMangoStore(walletSelector)
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const actions = useMangoStore((s) => s.actions)
|
||||
|
||||
|
@ -80,6 +80,9 @@ export default function Referral() {
|
|||
const referralTotalAmount = useMangoStore((s) => s.referrals.total)
|
||||
const hasReferrals = referralHistory.length > 0
|
||||
|
||||
const { wallet } = useWallet()
|
||||
const mangoStoreWallet = useMangoStore.getState().wallet.current
|
||||
|
||||
const [customRefLinkInput, setCustomRefLinkInput] = useState('')
|
||||
const [existingCustomRefLinks, setexistingCustomRefLinks] = useState<
|
||||
ReferrerIdRecord[]
|
||||
|
@ -144,6 +147,10 @@ export default function Referral() {
|
|||
}
|
||||
}
|
||||
|
||||
const handleConnect = useCallback(() => {
|
||||
handleWalletConnect(wallet)
|
||||
}, [wallet])
|
||||
|
||||
const submitRefLink = async () => {
|
||||
let encodedRefLink: string
|
||||
try {
|
||||
|
@ -161,7 +168,7 @@ export default function Referral() {
|
|||
const txid = await mangoClient.registerReferrerId(
|
||||
mangoGroup,
|
||||
mangoAccount,
|
||||
wallet,
|
||||
mangoStoreWallet,
|
||||
encodedRefLink
|
||||
)
|
||||
notify({
|
||||
|
@ -518,6 +525,7 @@ export default function Referral() {
|
|||
icon={<CurrencyDollarIcon />}
|
||||
onClickButton={() => setShowAccountsModal(true)}
|
||||
title={t('no-account-found')}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
@ -530,8 +538,9 @@ export default function Referral() {
|
|||
<div className="col-span-12 flex items-center justify-center rounded-md bg-th-bkg-3 p-6 lg:col-span-8">
|
||||
<EmptyState
|
||||
buttonText={t('connect')}
|
||||
disabled={!wallet || !mangoGroup}
|
||||
icon={<LinkIcon />}
|
||||
onClickButton={() => wallet.connect()}
|
||||
onClickButton={handleConnect}
|
||||
title={t('connect-wallet')}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -407,19 +407,19 @@ const useMangoStore = create<
|
|||
const wallet = get().wallet.current
|
||||
const actions = get().actions
|
||||
|
||||
if (!wallet?.publicKey || !mangoGroup) return
|
||||
|
||||
const delegateFilter = [
|
||||
{
|
||||
memcmp: {
|
||||
offset: MangoAccountLayout.offsetOf('delegate'),
|
||||
bytes: wallet?.publicKey.toBase58(),
|
||||
bytes: wallet?.publicKey?.toBase58(),
|
||||
},
|
||||
},
|
||||
]
|
||||
const accountSorter = (a, b) =>
|
||||
a.publicKey.toBase58() > b.publicKey.toBase58() ? 1 : -1
|
||||
|
||||
if (!wallet?.publicKey || !mangoGroup) return
|
||||
|
||||
return Promise.all([
|
||||
mangoClient.getMangoAccountsForOwner(
|
||||
mangoGroup,
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"resolveJsonModule": true,
|
||||
"jsx": "preserve",
|
||||
"isolatedModules": true,
|
||||
"incremental": true
|
||||
"incremental": true,
|
||||
"baseUrl": "."
|
||||
},
|
||||
"exclude": ["node_modules", ".next", "out", "public/datafeeds"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"]
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
import { PublicKey, Transaction } from '@solana/web3.js'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { WalletAdapter } from '../../@types/types'
|
||||
|
||||
interface BitpieWallet {
|
||||
getAccount(): Promise<string>
|
||||
signTransaction(transaction: Transaction): Promise<Transaction>
|
||||
signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>
|
||||
}
|
||||
|
||||
interface BitpieWalletWindow extends Window {
|
||||
bitpie?: BitpieWallet
|
||||
}
|
||||
|
||||
declare const window: BitpieWalletWindow
|
||||
|
||||
export class BitpieWalletAdapter extends EventEmitter implements WalletAdapter {
|
||||
private _connecting: boolean
|
||||
private _wallet: BitpieWallet | null
|
||||
private _publicKey: PublicKey | null
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this._connecting = false
|
||||
this._wallet = null
|
||||
this._publicKey = null
|
||||
}
|
||||
|
||||
get publicKey(): PublicKey | null {
|
||||
return this._publicKey
|
||||
}
|
||||
|
||||
get ready(): boolean {
|
||||
return typeof window !== 'undefined' && !!window.bitpie
|
||||
}
|
||||
|
||||
get connecting(): boolean {
|
||||
return this._connecting
|
||||
}
|
||||
|
||||
get connected(): boolean {
|
||||
return !!this._wallet
|
||||
}
|
||||
|
||||
get autoApprove() {
|
||||
return true
|
||||
}
|
||||
|
||||
async connect(): Promise<void> {
|
||||
try {
|
||||
if (this.connected || this.connecting) return
|
||||
this._connecting = true
|
||||
|
||||
const wallet = typeof window !== 'undefined' && window.bitpie
|
||||
if (!wallet) return
|
||||
|
||||
let account: string
|
||||
try {
|
||||
account = await wallet.getAccount()
|
||||
} catch (error: any) {
|
||||
notify({
|
||||
title: 'Connection Error',
|
||||
type: 'error',
|
||||
description:
|
||||
'Please install Bitpie wallet and then reload this page.',
|
||||
})
|
||||
}
|
||||
|
||||
this._wallet = wallet
|
||||
this._publicKey = new PublicKey(account)
|
||||
|
||||
this.emit('connect')
|
||||
} catch (error: any) {
|
||||
this.emit('error', error)
|
||||
throw error
|
||||
} finally {
|
||||
this._connecting = false
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
if (this._wallet) {
|
||||
this._wallet = null
|
||||
this._publicKey = null
|
||||
}
|
||||
|
||||
this.emit('disconnect')
|
||||
}
|
||||
|
||||
async signTransaction(transaction: Transaction): Promise<Transaction> {
|
||||
try {
|
||||
const wallet = this._wallet
|
||||
if (!wallet) return
|
||||
|
||||
return (await wallet.signTransaction(transaction)) || transaction
|
||||
} catch (error: any) {
|
||||
this.emit('error', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async signAllTransactions(
|
||||
transactions: Transaction[]
|
||||
): Promise<Transaction[]> {
|
||||
try {
|
||||
const wallet = this._wallet
|
||||
if (!wallet) return
|
||||
|
||||
return (await wallet.signAllTransactions(transactions)) || transactions
|
||||
} catch (error: any) {
|
||||
this.emit('error', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
import { PublicKey, Transaction } from '@solana/web3.js'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { DEFAULT_PUBLIC_KEY, WalletAdapter } from '../../@types/types'
|
||||
|
||||
type GlowEvent = 'disconnect' | 'connect'
|
||||
type GlowRequestMethod =
|
||||
| 'connect'
|
||||
| 'disconnect'
|
||||
| 'signTransaction'
|
||||
| 'signAllTransactions'
|
||||
|
||||
interface GlowProvider {
|
||||
publicKey?: PublicKey
|
||||
isConnected?: boolean
|
||||
autoApprove?: boolean
|
||||
signTransaction: (transaction: Transaction) => Promise<Transaction>
|
||||
signAllTransactions: (transactions: Transaction[]) => Promise<Transaction[]>
|
||||
connect: () => Promise<void>
|
||||
disconnect: () => Promise<void>
|
||||
on: (event: GlowEvent, handler: (args: any) => void) => void
|
||||
request: (method: GlowRequestMethod, params: any) => Promise<any>
|
||||
listeners: (event: GlowEvent) => (() => void)[]
|
||||
}
|
||||
|
||||
export class GlowWalletAdapter extends EventEmitter implements WalletAdapter {
|
||||
constructor() {
|
||||
super()
|
||||
this.connect = this.connect.bind(this)
|
||||
}
|
||||
|
||||
private get _provider(): GlowProvider | undefined {
|
||||
if ((window as any)?.glowSolana?.isGlow) {
|
||||
return (window as any).glowSolana
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private _handleConnect = (...args) => {
|
||||
this.emit('connect', ...args)
|
||||
}
|
||||
|
||||
private _handleDisconnect = (...args) => {
|
||||
this.emit('disconnect', ...args)
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return this._provider?.isConnected || false
|
||||
}
|
||||
|
||||
get autoApprove() {
|
||||
return this._provider?.autoApprove || false
|
||||
}
|
||||
|
||||
async signAllTransactions(
|
||||
transactions: Transaction[]
|
||||
): Promise<Transaction[]> {
|
||||
if (!this._provider) {
|
||||
return transactions
|
||||
}
|
||||
|
||||
return this._provider.signAllTransactions(transactions)
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
return this._provider?.publicKey || DEFAULT_PUBLIC_KEY
|
||||
}
|
||||
|
||||
async signTransaction(transaction: Transaction) {
|
||||
if (!this._provider) {
|
||||
return transaction
|
||||
}
|
||||
|
||||
return this._provider.signTransaction(transaction)
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (!this._provider) {
|
||||
window.open('https://glow.app/', '_blank')
|
||||
notify({
|
||||
title: 'Connection Error',
|
||||
type: 'error',
|
||||
description: 'Please install Glow wallet and then reload this page.',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this._provider.listeners('connect').length) {
|
||||
this._provider?.on('connect', this._handleConnect)
|
||||
}
|
||||
if (!this._provider.listeners('disconnect').length) {
|
||||
this._provider?.on('disconnect', this._handleDisconnect)
|
||||
}
|
||||
return this._provider?.connect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this._provider) {
|
||||
this._provider.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
import { PublicKey, Transaction } from '@solana/web3.js'
|
||||
import { DEFAULT_PUBLIC_KEY, WalletAdapter } from '../../@types/types'
|
||||
|
||||
type HuobiEvent = 'disconnect' | 'connect'
|
||||
type HuobiRequestMethod =
|
||||
| 'connect'
|
||||
| 'disconnect'
|
||||
| 'signTransaction'
|
||||
| 'signAllTransactions'
|
||||
|
||||
interface HuobiProvider {
|
||||
publicKey?: PublicKey
|
||||
isConnected?: boolean
|
||||
autoApprove?: boolean
|
||||
signTransaction: (transaction: Transaction) => Promise<Transaction>
|
||||
signAllTransactions: (transactions: Transaction[]) => Promise<Transaction[]>
|
||||
connect: () => Promise<void>
|
||||
disconnect: () => Promise<void>
|
||||
on: (event: HuobiEvent, handler: (args: any) => void) => void
|
||||
request: (method: HuobiRequestMethod, params: any) => Promise<any>
|
||||
listeners: (event: HuobiEvent) => (() => void)[]
|
||||
}
|
||||
|
||||
export class HuobiWalletAdapter extends EventEmitter implements WalletAdapter {
|
||||
constructor() {
|
||||
super()
|
||||
this.connect = this.connect.bind(this)
|
||||
}
|
||||
|
||||
private get _provider(): HuobiProvider | undefined {
|
||||
if ((window as any)?.huobiWallet?.isHuobiWallet) {
|
||||
return (window as any).huobiWallet
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private _handleConnect = (...args) => {
|
||||
this.emit('connect', ...args)
|
||||
}
|
||||
|
||||
private _handleDisconnect = (...args) => {
|
||||
this.emit('disconnect', ...args)
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return this._provider?.isConnected || false
|
||||
}
|
||||
|
||||
get autoApprove() {
|
||||
return this._provider?.autoApprove || false
|
||||
}
|
||||
|
||||
async signAllTransactions(
|
||||
transactions: Transaction[]
|
||||
): Promise<Transaction[]> {
|
||||
if (!this._provider) {
|
||||
return transactions
|
||||
}
|
||||
|
||||
return this._provider.signAllTransactions(transactions)
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
return this._provider?.publicKey || DEFAULT_PUBLIC_KEY
|
||||
}
|
||||
|
||||
async signTransaction(transaction: Transaction) {
|
||||
if (!this._provider) {
|
||||
return transaction
|
||||
}
|
||||
|
||||
return this._provider.signTransaction(transaction)
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (!this._provider) {
|
||||
return
|
||||
}
|
||||
if (!this._provider.listeners('connect').length) {
|
||||
this._provider?.on('connect', this._handleConnect)
|
||||
}
|
||||
if (!this._provider.listeners('disconnect').length) {
|
||||
this._provider?.on('disconnect', this._handleDisconnect)
|
||||
}
|
||||
return this._provider?.connect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this._provider) {
|
||||
this._provider.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,104 +0,0 @@
|
|||
import EventEmitter from 'eventemitter3'
|
||||
import { PublicKey, Transaction } from '@solana/web3.js'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { DEFAULT_PUBLIC_KEY, WalletAdapter } from '../../@types/types'
|
||||
|
||||
type PhantomEvent = 'disconnect' | 'connect'
|
||||
type PhantomRequestMethod =
|
||||
| 'connect'
|
||||
| 'disconnect'
|
||||
| 'signTransaction'
|
||||
| 'signAllTransactions'
|
||||
|
||||
interface PhantomProvider {
|
||||
publicKey?: PublicKey
|
||||
isConnected?: boolean
|
||||
autoApprove?: boolean
|
||||
signTransaction: (transaction: Transaction) => Promise<Transaction>
|
||||
signAllTransactions: (transactions: Transaction[]) => Promise<Transaction[]>
|
||||
connect: () => Promise<void>
|
||||
disconnect: () => Promise<void>
|
||||
on: (event: PhantomEvent, handler: (args: any) => void) => void
|
||||
request: (method: PhantomRequestMethod, params: any) => Promise<any>
|
||||
listeners: (event: PhantomEvent) => (() => void)[]
|
||||
}
|
||||
|
||||
export class PhantomWalletAdapter
|
||||
extends EventEmitter
|
||||
implements WalletAdapter
|
||||
{
|
||||
constructor() {
|
||||
super()
|
||||
this.connect = this.connect.bind(this)
|
||||
}
|
||||
|
||||
private get _provider(): PhantomProvider | undefined {
|
||||
if ((window as any)?.solana?.isPhantom) {
|
||||
return (window as any).solana
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
private _handleConnect = (...args) => {
|
||||
this.emit('connect', ...args)
|
||||
}
|
||||
|
||||
private _handleDisconnect = (...args) => {
|
||||
this.emit('disconnect', ...args)
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return this._provider?.isConnected || false
|
||||
}
|
||||
|
||||
get autoApprove() {
|
||||
return this._provider?.autoApprove || false
|
||||
}
|
||||
|
||||
async signAllTransactions(
|
||||
transactions: Transaction[]
|
||||
): Promise<Transaction[]> {
|
||||
if (!this._provider) {
|
||||
return transactions
|
||||
}
|
||||
|
||||
return this._provider.signAllTransactions(transactions)
|
||||
}
|
||||
|
||||
get publicKey() {
|
||||
return this._provider?.publicKey || DEFAULT_PUBLIC_KEY
|
||||
}
|
||||
|
||||
async signTransaction(transaction: Transaction) {
|
||||
if (!this._provider) {
|
||||
return transaction
|
||||
}
|
||||
|
||||
return this._provider.signTransaction(transaction)
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (!this._provider) {
|
||||
window.open('https://phantom.app/', '_blank')
|
||||
notify({
|
||||
title: 'Connection Error',
|
||||
type: 'error',
|
||||
description: 'Please install Phantom wallet and then reload this page.',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this._provider.listeners('connect').length) {
|
||||
this._provider?.on('connect', this._handleConnect)
|
||||
}
|
||||
if (!this._provider.listeners('disconnect').length) {
|
||||
this._provider?.on('disconnect', this._handleDisconnect)
|
||||
}
|
||||
return this._provider?.connect()
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this._provider) {
|
||||
this._provider.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
import { PublicKey, Transaction } from '@solana/web3.js'
|
||||
import bs58 from 'bs58'
|
||||
import EventEmitter from 'events'
|
||||
import { WalletAdapter } from '../../@types/types'
|
||||
import { notify } from '../notifications'
|
||||
|
||||
interface SlopeWallet {
|
||||
connect(): Promise<{
|
||||
msg: string
|
||||
data: {
|
||||
publicKey?: string
|
||||
}
|
||||
}>
|
||||
disconnect(): Promise<{ msg: string }>
|
||||
signTransaction(message: string): Promise<{
|
||||
msg: string
|
||||
data: {
|
||||
publicKey?: string
|
||||
signature?: string
|
||||
}
|
||||
}>
|
||||
signAllTransactions(messages: string[]): Promise<{
|
||||
msg: string
|
||||
data: {
|
||||
publicKey?: string
|
||||
signatures?: string[]
|
||||
}
|
||||
}>
|
||||
}
|
||||
|
||||
interface SlopeWindow extends Window {
|
||||
Slope?: {
|
||||
new (): SlopeWallet
|
||||
}
|
||||
}
|
||||
|
||||
declare const window: SlopeWindow
|
||||
|
||||
export class SlopeWalletAdapter extends EventEmitter implements WalletAdapter {
|
||||
private _connecting: boolean
|
||||
private _wallet: SlopeWallet | null
|
||||
private _publicKey: PublicKey | null
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this._connecting = false
|
||||
this._wallet = null
|
||||
this._publicKey = null
|
||||
}
|
||||
|
||||
get publicKey(): PublicKey | null {
|
||||
return this._publicKey
|
||||
}
|
||||
|
||||
get ready(): boolean {
|
||||
return typeof window !== 'undefined' && !!window.Slope
|
||||
}
|
||||
|
||||
get connecting(): boolean {
|
||||
return this._connecting
|
||||
}
|
||||
|
||||
get connected(): boolean {
|
||||
return !!this._publicKey
|
||||
}
|
||||
|
||||
get autoApprove() {
|
||||
return true
|
||||
}
|
||||
|
||||
async connect(): Promise<void> {
|
||||
try {
|
||||
if (this.connected || this.connecting) return
|
||||
this._connecting = true
|
||||
|
||||
const wallet = new window.Slope()
|
||||
const { data } = await wallet.connect()
|
||||
this._wallet = wallet
|
||||
this._publicKey = new PublicKey(data.publicKey)
|
||||
|
||||
this.emit('connect')
|
||||
} catch (error: any) {
|
||||
notify({
|
||||
title: 'Connection Error',
|
||||
type: 'error',
|
||||
description: 'Please install Slope wallet and then reload this page.',
|
||||
})
|
||||
} finally {
|
||||
this._connecting = false
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
const wallet = this._wallet
|
||||
if (wallet) {
|
||||
this._wallet = null
|
||||
this._publicKey = null
|
||||
await wallet.disconnect()
|
||||
this.emit('disconnect')
|
||||
}
|
||||
}
|
||||
|
||||
async signTransaction(transaction: Transaction): Promise<Transaction> {
|
||||
const wallet = this._wallet
|
||||
const message = bs58.encode(transaction.serializeMessage())
|
||||
const { data } = await wallet.signTransaction(message)
|
||||
const publicKey = new PublicKey(data.publicKey)
|
||||
const signature = bs58.decode(data.signature)
|
||||
|
||||
transaction.addSignature(publicKey, signature)
|
||||
return transaction
|
||||
}
|
||||
|
||||
async signAllTransactions(
|
||||
transactions: Transaction[]
|
||||
): Promise<Transaction[]> {
|
||||
const wallet = this._wallet
|
||||
const messages = transactions.map((transaction) =>
|
||||
bs58.encode(transaction.serializeMessage())
|
||||
)
|
||||
const { data } = await wallet.signAllTransactions(messages)
|
||||
|
||||
const length = transactions.length
|
||||
const publicKey = new PublicKey(data.publicKey)
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
transactions[i].addSignature(publicKey, bs58.decode(data.signatures[i]))
|
||||
}
|
||||
|
||||
return transactions
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import Solflare from '@solflare-wallet/sdk'
|
||||
|
||||
export function SolflareWalletAdapter(_, network) {
|
||||
return new Solflare({ network })
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import Wallet from '@project-serum/sol-wallet-adapter'
|
||||
import { notify } from '../../utils/notifications'
|
||||
|
||||
export function SolletExtensionAdapter(_, network) {
|
||||
const sollet = (window as any).sollet
|
||||
if (sollet) {
|
||||
return new Wallet(sollet, network)
|
||||
}
|
||||
|
||||
return {
|
||||
on: () => {},
|
||||
connect: () => {
|
||||
notify({
|
||||
title: 'Sollet Extension Error',
|
||||
type: 'error',
|
||||
description:
|
||||
'Please install the Sollet Extension for Chrome and then reload this page.',
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue