fix problem in wallet state mgmt

This commit is contained in:
Maximilian Schneider 2021-07-16 13:50:43 +02:00
parent 1c868995a1
commit 9b62f6ebf4
7 changed files with 81 additions and 155 deletions

View File

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

View File

@ -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" />

View File

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

View File

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

View File

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

View File

@ -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()],

View File

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