fix problem in wallet state mgmt
This commit is contained in:
parent
1c868995a1
commit
9b62f6ebf4
|
@ -1,19 +1,4 @@
|
|||
import {
|
||||
AccountInfo,
|
||||
Connection,
|
||||
PublicKey,
|
||||
Transaction,
|
||||
} from '@solana/web3.js'
|
||||
import Wallet from '@project-serum/sol-wallet-adapter'
|
||||
|
||||
export interface ConnectionContextValues {
|
||||
endpoint: string
|
||||
setEndpoint: (newEndpoint: string) => void
|
||||
connection: Connection
|
||||
sendConnection: Connection
|
||||
availableEndpoints: EndpointInfo[]
|
||||
setCustomEndpoints: (newCustomEndpoints: EndpointInfo[]) => void
|
||||
}
|
||||
import { AccountInfo, PublicKey, Transaction } from '@solana/web3.js'
|
||||
|
||||
export interface EndpointInfo {
|
||||
name: string
|
||||
|
@ -23,35 +8,12 @@ export interface EndpointInfo {
|
|||
poolKey: string
|
||||
}
|
||||
|
||||
export interface WalletContextValues {
|
||||
wallet: Wallet
|
||||
connected: boolean
|
||||
providerUrl: string
|
||||
setProviderUrl: (newProviderUrl: string) => void
|
||||
providerName: string
|
||||
}
|
||||
|
||||
export interface TokenAccount {
|
||||
pubkey: PublicKey
|
||||
account: AccountInfo<Buffer> | null
|
||||
effectiveMint: PublicKey
|
||||
}
|
||||
|
||||
/**
|
||||
* {tokenMint: preferred token account's base58 encoded public key}
|
||||
*/
|
||||
export interface SelectedTokenAccounts {
|
||||
[tokenMint: string]: string
|
||||
}
|
||||
|
||||
// Token infos
|
||||
export interface KnownToken {
|
||||
tokenSymbol: string
|
||||
tokenName: string
|
||||
icon?: string
|
||||
mintAddress: string
|
||||
}
|
||||
|
||||
export interface WalletAdapter {
|
||||
publicKey: PublicKey
|
||||
autoApprove: boolean
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { Menu } from '@headlessui/react'
|
||||
import { LinkIcon } from '@heroicons/react/solid'
|
||||
import useWallet, { WALLET_PROVIDERS } from '../hooks/useWallet'
|
||||
import { useMemo } from 'react'
|
||||
import useWalletStore from '../stores/useWalletStore'
|
||||
import {
|
||||
getWalletProviderByUrl,
|
||||
WALLET_PROVIDERS,
|
||||
} from '../utils/wallet-adapters'
|
||||
import Button from './Button'
|
||||
|
||||
const ChevronDownIcon = (props) => (
|
||||
|
@ -36,7 +41,15 @@ const CheckIcon = (props) => (
|
|||
)
|
||||
|
||||
const ConnectWalletButton = (props) => {
|
||||
const { connected, provider, setSavedProviderUrl } = useWallet()
|
||||
const {
|
||||
connected,
|
||||
selectedProviderUrl,
|
||||
set: setWalletStore,
|
||||
} = useWalletStore((s) => s)
|
||||
|
||||
const provider = useMemo(() => getWalletProviderByUrl(selectedProviderUrl), [
|
||||
selectedProviderUrl,
|
||||
])
|
||||
|
||||
return (
|
||||
<div className="flex">
|
||||
|
@ -65,7 +78,11 @@ const ConnectWalletButton = (props) => {
|
|||
<Menu.Item key={name}>
|
||||
<button
|
||||
className="flex p-2 h-9 hover:bg-bkg-2 hover:cursor-pointer hover:rounded-2xl font-normal focus:outline-none"
|
||||
onClick={() => setSavedProviderUrl(url)}
|
||||
onClick={() =>
|
||||
setWalletStore((s) => {
|
||||
s.providerUrl = url
|
||||
})
|
||||
}
|
||||
style={{ width: '14rem' }}
|
||||
>
|
||||
<img src={icon} className="h-4 w-4 mr-2" />
|
||||
|
|
|
@ -9,8 +9,8 @@ import useVaults from '../hooks/useVaults'
|
|||
|
||||
const RedeemModal = () => {
|
||||
const actions = useWalletStore((s) => s.actions)
|
||||
const connected = useWalletStore((s) => s.connected)
|
||||
const wallet = useWalletStore((s) => s.current)
|
||||
const connected = useWalletStore((s) => s.connected)
|
||||
const largestAccounts = useLargestAccounts()
|
||||
const vaults = useVaults()
|
||||
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
import { Menu } from '@headlessui/react'
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon,
|
||||
CheckCircleIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
|
||||
import useWalletStore from '../stores/useWalletStore'
|
||||
import { WALLET_PROVIDERS, DEFAULT_PROVIDER } from '../hooks/useWallet'
|
||||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
|
||||
export default function WalletSelect({ isPrimary = false }) {
|
||||
const setWalletStore = useWalletStore((s) => s.set)
|
||||
const [savedProviderUrl] = useLocalStorageState(
|
||||
'walletProvider',
|
||||
DEFAULT_PROVIDER.url
|
||||
)
|
||||
|
||||
const handleSelectProvider = (url) => {
|
||||
setWalletStore((state) => {
|
||||
state.providerUrl = url
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Menu.Button
|
||||
className={`flex justify-center items-center h-full rounded-r rounded-l-none focus:outline-none text-primary hover:text-fgd-1 ${
|
||||
isPrimary
|
||||
? 'px-3 hover:bg-primary'
|
||||
: 'px-2 hover:bg-bkg-3 border-l border-fgd-4'
|
||||
} cursor-pointer`}
|
||||
>
|
||||
{open ? (
|
||||
<ChevronUpIcon className="h-5 w-5" />
|
||||
) : (
|
||||
<ChevronDownIcon className="h-5 w-5" />
|
||||
)}
|
||||
</Menu.Button>
|
||||
<Menu.Items className="z-20 p-1 absolute right-0 top-11 bg-bkg-1 divide-y divide-bkg-3 shadow-lg outline-none rounded-md w-48">
|
||||
{WALLET_PROVIDERS.map(({ name, url, icon }) => (
|
||||
<Menu.Item key={name}>
|
||||
<button
|
||||
className="flex flex-row items-center justify-between w-full p-2 hover:bg-bkg-2 hover:cursor-pointer font-normal focus:outline-none"
|
||||
onClick={() => handleSelectProvider(url)}
|
||||
>
|
||||
<div className="flex">
|
||||
<img src={icon} className="w-5 h-5 mr-2" />
|
||||
{name}
|
||||
</div>
|
||||
{savedProviderUrl === url ? (
|
||||
<CheckCircleIcon className="h-4 w-4 text-green" />
|
||||
) : null}{' '}
|
||||
</button>
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</>
|
||||
)}
|
||||
</Menu>
|
||||
)
|
||||
}
|
|
@ -1,41 +1,17 @@
|
|||
import { useEffect, useMemo } from 'react'
|
||||
import Wallet from '@project-serum/sol-wallet-adapter'
|
||||
|
||||
import { WalletAdapter } from '../@types/types'
|
||||
import useWalletStore from '../stores/useWalletStore'
|
||||
import { notify } from '../utils/notifications'
|
||||
import {
|
||||
PhantomWalletAdapter,
|
||||
SolletExtensionAdapter,
|
||||
DEFAULT_PROVIDER,
|
||||
getWalletProviderByUrl,
|
||||
} from '../utils/wallet-adapters'
|
||||
|
||||
import useInterval from './useInterval'
|
||||
import useLocalStorageState from './useLocalStorageState'
|
||||
|
||||
const SECONDS = 1000
|
||||
const ASSET_URL =
|
||||
'https://cdn.jsdelivr.net/gh/solana-labs/oyster@main/assets/wallets'
|
||||
|
||||
export const WALLET_PROVIDERS = [
|
||||
{
|
||||
name: 'Sollet.io',
|
||||
url: 'https://www.sollet.io',
|
||||
icon: `${ASSET_URL}/sollet.svg`,
|
||||
},
|
||||
{
|
||||
name: 'Sollet Extension',
|
||||
url: 'https://www.sollet.io/extension',
|
||||
icon: `${ASSET_URL}/sollet.svg`,
|
||||
adapter: SolletExtensionAdapter as any,
|
||||
},
|
||||
{
|
||||
name: 'Phantom',
|
||||
url: 'https://www.phantom.app',
|
||||
icon: `https://www.phantom.app/img/logo.png`,
|
||||
adapter: PhantomWalletAdapter,
|
||||
},
|
||||
]
|
||||
|
||||
export const DEFAULT_PROVIDER = WALLET_PROVIDERS[0]
|
||||
|
||||
export default function useWallet() {
|
||||
const {
|
||||
|
@ -50,13 +26,12 @@ export default function useWallet() {
|
|||
'walletProvider',
|
||||
DEFAULT_PROVIDER.url
|
||||
)
|
||||
const provider = useMemo(
|
||||
() => WALLET_PROVIDERS.find(({ url }) => url === savedProviderUrl),
|
||||
[savedProviderUrl]
|
||||
)
|
||||
const provider = useMemo(() => getWalletProviderByUrl(selectedProviderUrl), [
|
||||
selectedProviderUrl,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProviderUrl) {
|
||||
if (selectedProviderUrl && selectedProviderUrl != savedProviderUrl) {
|
||||
setSavedProviderUrl(selectedProviderUrl)
|
||||
}
|
||||
}, [selectedProviderUrl])
|
||||
|
@ -65,8 +40,8 @@ export default function useWallet() {
|
|||
if (provider) {
|
||||
const updateWallet = () => {
|
||||
// hack to also update wallet synchronously in case it disconnects
|
||||
const wallet = new (provider.adapter || Wallet)(
|
||||
savedProviderUrl,
|
||||
const wallet = new provider.adapter(
|
||||
provider.url,
|
||||
endpoint
|
||||
) as WalletAdapter
|
||||
setWalletStore((state) => {
|
||||
|
@ -86,7 +61,7 @@ export default function useWallet() {
|
|||
updateWallet()
|
||||
}
|
||||
}
|
||||
}, [provider, savedProviderUrl, endpoint])
|
||||
}, [provider, endpoint])
|
||||
|
||||
useEffect(() => {
|
||||
if (!wallet) return
|
||||
|
@ -116,14 +91,14 @@ export default function useWallet() {
|
|||
})
|
||||
})
|
||||
return () => {
|
||||
if (wallet && wallet.connected) {
|
||||
if (wallet) {
|
||||
wallet.disconnect()
|
||||
}
|
||||
setWalletStore((state) => {
|
||||
state.connected = false
|
||||
})
|
||||
}
|
||||
}, [wallet, setWalletStore])
|
||||
}, [wallet])
|
||||
|
||||
// fetch pool on page load
|
||||
useEffect(() => {
|
||||
|
@ -139,5 +114,5 @@ export default function useWallet() {
|
|||
actions.fetchUsdcVault()
|
||||
}, 20 * SECONDS)
|
||||
|
||||
return { connected, wallet, provider, setSavedProviderUrl }
|
||||
return { connected, wallet }
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import { findLargestBalanceAccountForMint } from '../hooks/useLargestAccounts'
|
|||
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'
|
||||
import { createAssociatedTokenAccount } from '../utils/associated'
|
||||
import { sendTransaction } from '../utils/send'
|
||||
import { DEFAULT_PROVIDER } from '../utils/wallet-adapters'
|
||||
|
||||
export const ENDPOINTS: EndpointInfo[] = [
|
||||
{
|
||||
|
@ -97,7 +98,7 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
programId: PROGRAM_ID,
|
||||
},
|
||||
current: null,
|
||||
providerUrl: null,
|
||||
providerUrl: DEFAULT_PROVIDER.url,
|
||||
provider: undefined,
|
||||
program: undefined,
|
||||
pool: undefined,
|
||||
|
@ -112,7 +113,7 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
const programId = get().connection.programId
|
||||
const set = get().set
|
||||
|
||||
console.log('fetchPool', connection, poolIdl)
|
||||
// console.log('fetchPool', connection, poolIdl)
|
||||
if (connection) {
|
||||
const provider = new anchor.Provider(
|
||||
connection,
|
||||
|
@ -129,7 +130,7 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
getTokenAccount(connection, pool.poolWatermelon),
|
||||
])
|
||||
|
||||
console.log({ program, pool, usdcVault, mangoVault })
|
||||
// console.log('fetchPool', { program, pool, usdcVault, mangoVault })
|
||||
|
||||
set((state) => {
|
||||
state.provider = provider
|
||||
|
@ -147,6 +148,12 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
const walletOwner = wallet?.publicKey
|
||||
const set = get().set
|
||||
|
||||
console.log(
|
||||
'fetchWalletTokenAccounts',
|
||||
connected,
|
||||
walletOwner?.toString()
|
||||
)
|
||||
|
||||
if (connected && walletOwner) {
|
||||
const ownedTokenAccounts = await getOwnedTokenAccounts(
|
||||
connection,
|
||||
|
@ -190,12 +197,12 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
const mints = await Promise.all(
|
||||
mintKeys.map((pk) => getMint(connection, pk))
|
||||
)
|
||||
console.log('fetchMints', mints)
|
||||
// console.log('fetchMints', mints)
|
||||
|
||||
set((state) => {
|
||||
for (const pa of mints) {
|
||||
state.mints[pa.publicKey.toBase58()] = pa.account
|
||||
console.log('mint', pa.publicKey.toBase58(), pa.account)
|
||||
// console.log('mint', pa.publicKey.toBase58(), pa.account)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -293,8 +300,6 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
actions.fetchUsdcVault()
|
||||
},
|
||||
async redeem() {
|
||||
console.log('redeem')
|
||||
|
||||
const actions = get().actions
|
||||
await actions.fetchWalletTokenAccounts()
|
||||
|
||||
|
@ -306,6 +311,7 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
current: wallet,
|
||||
connection: { current: connection },
|
||||
} = get()
|
||||
|
||||
const redeemable = findLargestBalanceAccountForMint(
|
||||
mints,
|
||||
tokenAccounts,
|
||||
|
@ -317,7 +323,7 @@ const useWalletStore = create<WalletStore>((set, get) => ({
|
|||
pool.watermelonMint
|
||||
)
|
||||
|
||||
console.log(redeemable, watermelon, 'exchangeRedeemableForMango')
|
||||
console.log('exchangeRedeemableForMango', redeemable, watermelon)
|
||||
|
||||
const [poolSigner] = await anchor.web3.PublicKey.findProgramAddress(
|
||||
[pool.watermelonMint.toBuffer()],
|
||||
|
|
|
@ -1,2 +1,32 @@
|
|||
export * from './phantom'
|
||||
export * from './sollet-extension'
|
||||
import Wallet from '@project-serum/sol-wallet-adapter'
|
||||
import { PhantomWalletAdapter } from './phantom'
|
||||
import { SolletExtensionAdapter } from './sollet-extension'
|
||||
|
||||
const ASSET_URL =
|
||||
'https://cdn.jsdelivr.net/gh/solana-labs/oyster@main/assets/wallets'
|
||||
|
||||
export const WALLET_PROVIDERS = [
|
||||
{
|
||||
name: 'Sollet.io',
|
||||
url: 'https://www.sollet.io',
|
||||
icon: `${ASSET_URL}/sollet.svg`,
|
||||
adapter: Wallet,
|
||||
},
|
||||
{
|
||||
name: 'Sollet Extension',
|
||||
url: 'https://www.sollet.io/extension',
|
||||
icon: `${ASSET_URL}/sollet.svg`,
|
||||
adapter: SolletExtensionAdapter as any,
|
||||
},
|
||||
{
|
||||
name: 'Phantom',
|
||||
url: 'https://www.phantom.app',
|
||||
icon: `https://www.phantom.app/img/logo.png`,
|
||||
adapter: PhantomWalletAdapter,
|
||||
},
|
||||
]
|
||||
|
||||
export const DEFAULT_PROVIDER = WALLET_PROVIDERS[0]
|
||||
|
||||
export const getWalletProviderByUrl = (urlOrNull) =>
|
||||
WALLET_PROVIDERS.find(({ url }) => url === urlOrNull) || DEFAULT_PROVIDER
|
||||
|
|
Loading…
Reference in New Issue