From dbf0e630e7e7c1e3bd77239a60aa9d4b59974d34 Mon Sep 17 00:00:00 2001 From: Marcus Pasell <3690498+rickyrombo@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:49:54 -0700 Subject: [PATCH 1/2] Wait for payout wallet retrieval from RPC before sending to ACDC, and show toast/spinner error if failed to load --- .../payout-wallet-modal/PayoutWalletModal.tsx | 45 ++++++++++++------- .../components/PayoutWalletCard.tsx | 36 ++++++++++----- packages/web/src/services/solana/solana.ts | 13 +----- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx b/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx index 7c951648e10..06742605e44 100644 --- a/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx +++ b/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx @@ -195,10 +195,8 @@ export const PayoutWalletModal = () => { const usdcMint = new PublicKey(env.USDC_MINT_ADDRESS) const addressPubkey = new PublicKey(address) - const info = - await sdk.services.claimableTokensClient.connection.getAccountInfo( - addressPubkey - ) + const connection = sdk.services.claimableTokensClient.connection + const info = await connection.getAccountInfo(addressPubkey) let usdcAta: string | null = null @@ -218,7 +216,7 @@ export const PayoutWalletModal = () => { usdcAta = address } } catch (e) { - console.debug(e) + console.debug(`Account ${address} is not a token account`, e) // fall through } } else { @@ -228,10 +226,7 @@ export const PayoutWalletModal = () => { addressPubkey ) try { - const account = await getAccount( - sdk.services.claimableTokensClient.connection, - ataPubkey - ) + const account = await getAccount(connection, ataPubkey) if (account.mint.equals(usdcMint)) { usdcAta = ataPubkey.toBase58() } @@ -239,8 +234,10 @@ export const PayoutWalletModal = () => { // No USDC mint ATA. Make one if possible. if (e instanceof TokenAccountNotFoundError) { const payer = await sdk.services.solanaRelay.getFeePayer() + const res = await connection.getLatestBlockhash() const transaction = await sdk.services.claimableTokensClient.buildTransaction({ + recentBlockhash: res.blockhash, instructions: [ createAssociatedTokenAccountIdempotentInstruction( payer, @@ -254,13 +251,31 @@ export const PayoutWalletModal = () => { ] }) - await sdk.services.solanaRelay.relay({ - transaction, - confirmationOptions: { - commitment: 'confirmed' - } + const { signature } = await sdk.services.solanaRelay.relay({ + transaction }) usdcAta = ataPubkey.toBase58() + await connection.confirmTransaction({ + signature, + blockhash: res.blockhash, + lastValidBlockHeight: res.lastValidBlockHeight + }) + let owner = null + let retryCount = 0 + // Obscene max retry count is intentional + while (owner === null && retryCount < 10000) { + try { + owner = await getAssociatedTokenAccountOwner( + usdcAta as SolanaWalletAddress + ) + } catch (e) { + console.debug( + 'Retry getAssociatedTokenAccountOwner...', + retryCount++ + ) + await new Promise((resolve) => setTimeout(resolve, 500)) + } + } } } } @@ -295,7 +310,7 @@ export const PayoutWalletModal = () => { const owner = await getAssociatedTokenAccountOwner( user.spl_usdc_payout_wallet ) - return owner.toString() + return owner?.toString() } return null }, [user]) diff --git a/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx b/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx index 6720d78c0ee..f4736832024 100644 --- a/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx +++ b/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useContext } from 'react' import { accountSelectors } from '@audius/common/store' import { shortenSPLAddress } from '@audius/common/utils' @@ -6,6 +6,7 @@ import { Flex, IconLogoCircle, IconLogoCircleUSDC, + LoadingSpinner, Paper, Text, TextLink @@ -15,6 +16,7 @@ import { useAsync } from 'react-use' import { useModalState } from 'common/hooks/useModalState' import { getAssociatedTokenAccountOwner } from 'services/solana/solana' +import { ToastContext } from 'components/toast/ToastContext' const { getAccountUser } = accountSelectors @@ -28,6 +30,7 @@ const messages = { export const PayoutWalletCard = () => { const user = useSelector(getAccountUser) const [, setIsOpen] = useModalState('PayoutWallet') + const { toast } = useContext(ToastContext) const handleChangeWallet = useCallback(() => { setIsOpen(true) @@ -35,13 +38,18 @@ export const PayoutWalletCard = () => { const { value: payoutWallet } = useAsync(async () => { if (user?.spl_usdc_payout_wallet) { - const owner = await getAssociatedTokenAccountOwner( - user.spl_usdc_payout_wallet - ) - return owner.toBase58() + try { + const owner = await getAssociatedTokenAccountOwner( + user.spl_usdc_payout_wallet + ) + return owner.toBase58() + } catch (e) { + toast('Failed to load USDC payout wallet') + return null + } } return null - }, [user]) + }, [user?.spl_usdc_payout_wallet]) return ( @@ -71,11 +79,17 @@ export const PayoutWalletCard = () => { )} - {user?.spl_usdc_payout_wallet - ? payoutWallet - ? shortenSPLAddress(payoutWallet) - : '' - : messages.audiusWallet} + {user?.spl_usdc_payout_wallet ? ( + payoutWallet ? ( + shortenSPLAddress(payoutWallet) + ) : ( + + + + ) + ) : ( + messages.audiusWallet + )} { const connection = await getSolanaConnection() - try { - const { owner } = await getAccount( - connection, - new PublicKey(accountAddress) - ) - return owner - } catch (e) { - // Not a token account, so return the provided address - console.error(e) - return new PublicKey(accountAddress) - } + const { owner } = await getAccount(connection, new PublicKey(accountAddress)) + return owner } /** From 618eafe19a7dea5c834507e2f34da860c62894fb Mon Sep 17 00:00:00 2001 From: Marcus Pasell <3690498+rickyrombo@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:51:03 -0700 Subject: [PATCH 2/2] order --- .../src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx b/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx index f4736832024..341ea353cff 100644 --- a/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx +++ b/packages/web/src/pages/pay-and-earn-page/components/PayoutWalletCard.tsx @@ -15,8 +15,8 @@ import { useSelector } from 'react-redux' import { useAsync } from 'react-use' import { useModalState } from 'common/hooks/useModalState' -import { getAssociatedTokenAccountOwner } from 'services/solana/solana' import { ToastContext } from 'components/toast/ToastContext' +import { getAssociatedTokenAccountOwner } from 'services/solana/solana' const { getAccountUser } = accountSelectors