From 9b62f6ebf47e696a6ec2d42415af849e59b0788e Mon Sep 17 00:00:00 2001 From: Maximilian Schneider Date: Fri, 16 Jul 2021 13:50:43 +0200 Subject: [PATCH] fix problem in wallet state mgmt --- @types/types.tsx | 40 +------------------ components/ConnectWalletButton.tsx | 23 +++++++++-- components/RedeemModal.tsx | 2 +- components/WalletSelect.tsx | 64 ------------------------------ hooks/useWallet.tsx | 51 ++++++------------------ stores/useWalletStore.tsx | 22 ++++++---- utils/wallet-adapters/index.ts | 34 +++++++++++++++- 7 files changed, 81 insertions(+), 155 deletions(-) delete mode 100644 components/WalletSelect.tsx diff --git a/@types/types.tsx b/@types/types.tsx index 8dd2f80..da331c6 100644 --- a/@types/types.tsx +++ b/@types/types.tsx @@ -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 | 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 diff --git a/components/ConnectWalletButton.tsx b/components/ConnectWalletButton.tsx index e6fff2b..e3703c7 100644 --- a/components/ConnectWalletButton.tsx +++ b/components/ConnectWalletButton.tsx @@ -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 (
@@ -65,7 +78,11 @@ const ConnectWalletButton = (props) => { - - ))} - - - )} - - ) -} diff --git a/hooks/useWallet.tsx b/hooks/useWallet.tsx index 7e07dc4..f006220 100644 --- a/hooks/useWallet.tsx +++ b/hooks/useWallet.tsx @@ -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 } } diff --git a/stores/useWalletStore.tsx b/stores/useWalletStore.tsx index 065af45..a27d2ac 100644 --- a/stores/useWalletStore.tsx +++ b/stores/useWalletStore.tsx @@ -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((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((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((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((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((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((set, get) => ({ actions.fetchUsdcVault() }, async redeem() { - console.log('redeem') - const actions = get().actions await actions.fetchWalletTokenAccounts() @@ -306,6 +311,7 @@ const useWalletStore = create((set, get) => ({ current: wallet, connection: { current: connection }, } = get() + const redeemable = findLargestBalanceAccountForMint( mints, tokenAccounts, @@ -317,7 +323,7 @@ const useWalletStore = create((set, get) => ({ pool.watermelonMint ) - console.log(redeemable, watermelon, 'exchangeRedeemableForMango') + console.log('exchangeRedeemableForMango', redeemable, watermelon) const [poolSigner] = await anchor.web3.PublicKey.findProgramAddress( [pool.watermelonMint.toBuffer()], diff --git a/utils/wallet-adapters/index.ts b/utils/wallet-adapters/index.ts index db683c6..4d06ef3 100644 --- a/utils/wallet-adapters/index.ts +++ b/utils/wallet-adapters/index.ts @@ -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