diff --git a/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx b/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx
index 0c899adf21a..8cd2c7a9e3f 100644
--- a/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx
+++ b/packages/web/src/components/payout-wallet-modal/PayoutWalletModal.tsx
@@ -19,13 +19,19 @@ import {
} from '@audius/harmony'
import { Formik, useField } from 'formik'
import { useDispatch, useSelector } from 'react-redux'
+import { useAsync } from 'react-use'
import { z } from 'zod'
import { toFormikValidationSchema } from 'zod-formik-adapter'
import { useModalState } from 'common/hooks/useModalState'
import { TextField } from 'components/form-fields'
import { ModalForm } from 'components/modal-form/ModalForm'
-import { isValidSolAddress } from 'services/solana/solana'
+import {
+ getAssociatedTokenAccountOwner,
+ isTokenAccount,
+ isValidSolAddress
+} from 'services/solana/solana'
+import { reportToSentry } from 'store/errors/reportToSentry'
const { getAccountUser } = accountSelectors
@@ -148,9 +154,24 @@ export const PayoutWalletModal = () => {
}, [setIsOpen])
const handleSubmit = useCallback(
- ({ option, address }: PayoutWalletValues) => {
- // TODO: Token account validation
- if (user) {
+ async (
+ { option, address }: PayoutWalletValues,
+ { setErrors }: { setErrors: any }
+ ) => {
+ try {
+ if (!address || !user) {
+ throw new Error('No user or address')
+ }
+
+ const isUsdcAta = await isTokenAccount({
+ accountAddress: address as SolanaWalletAddress,
+ mint: 'usdc'
+ })
+ if (!isUsdcAta) {
+ // Create ATA via relay
+ throw new Error('Create ATA not implemented')
+ }
+
const updatedUser = { ...user }
if (option === 'default') {
updatedUser.spl_usdc_payout_wallet = null
@@ -158,16 +179,32 @@ export const PayoutWalletModal = () => {
updatedUser.spl_usdc_payout_wallet = address as SolanaWalletAddress
}
dispatch(profilePageActions.updateProfile(updatedUser))
+ setIsOpen(false)
+ } catch (e) {
+ setErrors({ address: 'Please try again later' })
+ await reportToSentry({
+ error: e as Error,
+ name: 'Payout Wallet: Error setting wallet'
+ })
}
- setIsOpen(false)
},
[dispatch, user, setIsOpen]
)
+ const { value: payoutWallet } = useAsync(async () => {
+ if (user?.spl_usdc_payout_wallet) {
+ const owner = await getAssociatedTokenAccountOwner(
+ user.spl_usdc_payout_wallet
+ )
+ return owner.toString()
+ }
+ return null
+ }, [user])
+
const initialValues: PayoutWalletValues = user?.spl_usdc_payout_wallet
? {
option: 'custom',
- address: user.spl_usdc_payout_wallet as string
+ address: payoutWallet ?? ''
}
: { option: 'default' }
@@ -177,6 +214,7 @@ export const PayoutWalletModal = () => {
} />
{
setIsOpen(true)
}, [setIsOpen])
+ const { value: payoutWallet } = useAsync(async () => {
+ if (user?.spl_usdc_payout_wallet) {
+ const owner = await getAssociatedTokenAccountOwner(
+ user.spl_usdc_payout_wallet
+ )
+ return owner.toBase58()
+ }
+ return null
+ }, [user])
+
return (
@@ -58,8 +71,8 @@ export const PayoutWalletCard = () => {
)}
- {user?.spl_usdc_payout_wallet
- ? shortenSPLAddress(user?.spl_usdc_payout_wallet)
+ {payoutWallet
+ ? shortenSPLAddress(payoutWallet)
: messages.audiusWallet}
diff --git a/packages/web/src/services/solana/solana.ts b/packages/web/src/services/solana/solana.ts
index 6e9daf8aa24..d74f65817bf 100644
--- a/packages/web/src/services/solana/solana.ts
+++ b/packages/web/src/services/solana/solana.ts
@@ -3,7 +3,8 @@ import { DEFAULT_MINT, MintName } from '@audius/common/services'
import {
Account,
getMinimumBalanceForRentExemptAccount,
- getAssociatedTokenAddressSync
+ getAssociatedTokenAddressSync,
+ getAccount
} from '@solana/spl-token'
import { PublicKey, Transaction, Keypair } from '@solana/web3.js'
@@ -143,6 +144,27 @@ export const getUSDCAssociatedTokenAccount = async (
)
}
+/**
+ * Returns the owner of the token acccount, if the provided account
+ * is a token account. Otherwise, just returns the account
+ */
+export const getAssociatedTokenAccountOwner = async (
+ accountAddress: SolanaWalletAddress
+) => {
+ 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)
+ }
+}
+
/**
* Returns the current user's USDC user bank.
*/