Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Wire up withdraw USDC saga to modal state #4045

Merged
merged 3 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/common/src/store/ui/withdraw-usdc/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,14 @@ const slice = createSlice({
setAmountFailed: (state, action: PayloadAction<{ error: Error }>) => {
state.amountError = action.payload.error
},
beginWithdrawUSDC: (state) => {
beginWithdrawUSDC: (
state,
_action: PayloadAction<{
amount: number
destinationAddress: string
onSuccess: (transaction: string) => void
}>
) => {
state.withdrawStatus = Status.LOADING
},
withdrawUSDCSucceeded: (state) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { useCallback } from 'react'

import {
SolanaWalletAddress,
useUSDCBalance,
useWithdrawUSDCModal,
WithdrawUSDCModalPages
WithdrawUSDCModalPages,
withdrawUSDCActions
} from '@audius/common'
import { Modal, ModalContent, ModalHeader } from '@audius/stems'
import { Formik } from 'formik'
import { useDispatch } from 'react-redux'
import { z } from 'zod'
import { toFormikValidationSchema } from 'zod-formik-adapter'

Expand All @@ -20,6 +24,8 @@ import { EnterTransferDetails } from './components/EnterTransferDetails'
import { TransferInProgress } from './components/TransferInProgress'
import { TransferSuccessful } from './components/TransferSuccessful'

const { beginWithdrawUSDC } = withdrawUSDCActions

const messages = {
title: 'Withdraw Funds',
errors: {
Expand Down Expand Up @@ -49,10 +55,34 @@ const WithdrawUSDCFormSchema = (userBalance: number) => {
}

export const WithdrawUSDCModal = () => {
const { isOpen, onClose, onClosed, data } = useWithdrawUSDCModal()
const dispatch = useDispatch()
const { isOpen, onClose, onClosed, data, setData } = useWithdrawUSDCModal()
const { page } = data
const { data: balance } = useUSDCBalance()

const onSuccess = useCallback(
(signature: string) => {
setData({
page: WithdrawUSDCModalPages.TRANSFER_SUCCESSFUL,
signature
})
},
[setData]
)

const handleSubmit = useCallback(
({ amount, address }: { amount: number; address: string }) => {
dispatch(
beginWithdrawUSDC({
amount,
destinationAddress: address,
onSuccess
})
)
},
[dispatch, onSuccess]
)

let formPage
switch (page) {
case WithdrawUSDCModalPages.ENTER_TRANSFER_DETAILS:
Expand Down Expand Up @@ -90,15 +120,15 @@ export const WithdrawUSDCModal = () => {
</ModalHeader>
<ModalContent>
<Formik
initialValues={{ [AMOUNT]: balance, [ADDRESS]: '', [CONFIRM]: false }}
initialValues={{
[AMOUNT]: balance?.toNumber() ?? 0,
[ADDRESS]: '',
[CONFIRM]: false
}}
validationSchema={toFormikValidationSchema(
WithdrawUSDCFormSchema(balance?.toNumber() ?? 0)
)}
// TODO -- call sagas to withdraw
// Saga in turn should update modal state to advance page
onSubmit={(values) => {
console.info(values)
}}
onSubmit={handleSubmit}
>
{formPage}
</Formik>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
AMOUNT,
CONFIRM
} from 'components/withdraw-usdc-modal/WithdrawUSDCModal'
import { toHumanReadable } from 'utils/tokenInput'

import styles from './ConfirmTransferDetails.module.css'
import { Hint } from './Hint'
Expand Down Expand Up @@ -56,7 +57,10 @@ export const ConfirmTransferDetails = () => {
return (
<div className={styles.root}>
<div className={styles.amount}>
<TextRow left={messages.amountToWithdraw} right={`-$${amountValue}`} />
<TextRow
left={messages.amountToWithdraw}
right={`-$${toHumanReadable(amountValue)}`}
/>
</div>
<Divider style={{ margin: 0 }} />
<div className={styles.destination}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ADDRESS,
AMOUNT
} from 'components/withdraw-usdc-modal/WithdrawUSDCModal'
import { toHumanReadable } from 'utils/tokenInput'

import { TextRow } from './TextRow'
import styles from './TransferInProgress.module.css'
Expand All @@ -40,7 +41,10 @@ export const TransferInProgress = () => {
left={messages.currentBalance}
right={`$${balanceFormatted}`}
/>
<TextRow left={messages.amountToWithdraw} right={`-$${amountValue}`} />
<TextRow
left={messages.amountToWithdraw}
right={`-$${toHumanReadable(amountValue)}`}
/>
</div>
<Divider style={{ margin: 0 }} />
<div className={styles.destination}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ADDRESS,
AMOUNT
} from 'components/withdraw-usdc-modal/WithdrawUSDCModal'
import { toHumanReadable } from 'utils/tokenInput'

import { TextRow } from './TextRow'
import styles from './TransferSuccessful.module.css'
Expand Down Expand Up @@ -56,7 +57,10 @@ export const TransferSuccessful = () => {
return (
<div className={styles.root}>
<Divider style={{ margin: 0 }} />
<TextRow left={messages.amountWithdrawn} right={`-$${amountValue}`} />
<TextRow
left={messages.amountWithdrawn}
right={`-$${toHumanReadable(amountValue)}`}
/>
<Divider style={{ margin: 0 }} />
<div className={styles.newBalance}>
<TextRow left={messages.newBalance} right={`$${balanceFormatted}`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { TextField, TextFieldProps } from 'components/form-fields'
import layoutStyles from 'components/layout/layout.module.css'
import { Text } from 'components/typography'
import {
PRECISION,
onTokenInputBlur,
onTokenInputChange
onTokenInputChange,
toHumanReadable
} from 'utils/tokenInput'

import { PREVIEW, PRICE } from '../AccessAndSaleField'
Expand Down Expand Up @@ -94,7 +94,7 @@ const PriceField = (props: TrackAvailabilityFieldsProps) => {
const { disabled } = props
const [{ value }, , { setValue: setPrice }] = useField<number>(PRICE)
const [humanizedValue, setHumanizedValue] = useState(
value ? (value / 100).toFixed(PRECISION) : null
value ? toHumanReadable(value) : null
)

const handlePriceChange: ChangeEventHandler<HTMLInputElement> = useCallback(
Expand Down
24 changes: 14 additions & 10 deletions packages/web/src/store/application/ui/withdraw-usdc/sagas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
withdrawUSDCActions,
withdrawUSDCSelectors,
solanaSelectors,
ErrorLevel,
SolanaWalletAddress,
Expand Down Expand Up @@ -47,10 +46,9 @@ const {
setDestinationAddress,
setDestinationAddressFailed,
setDestinationAddressSucceeded,
withdrawUSDCFailed
withdrawUSDCFailed,
withdrawUSDCSucceeded
} = withdrawUSDCActions
const { getWithdrawDestinationAddress, getWithdrawAmount } =
withdrawUSDCSelectors
const { getFeePayer } = solanaSelectors

function* doSetAmount({ payload: { amount } }: ReturnType<typeof setAmount>) {
Expand Down Expand Up @@ -109,15 +107,18 @@ function* doSetDestinationAddress({
}
}

function* doWithdrawUSDC({ payload }: ReturnType<typeof beginWithdrawUSDC>) {
/**
* Handles all logic for withdrawing USDC to a given destination. Expects amount in dollars.
*/
function* doWithdrawUSDC({
payload: { amount, destinationAddress, onSuccess }
}: ReturnType<typeof beginWithdrawUSDC>) {
try {
const libs = yield* call(getLibs)
if (!libs.solanaWeb3Manager) {
throw new Error('Failed to get solana web3 manager')
}
// Assume destinationAddress and amount have already been validated
const destinationAddress = yield* select(getWithdrawDestinationAddress)
const amount = yield* select(getWithdrawAmount)
if (!destinationAddress || !amount) {
throw new Error('Please enter a valid destination address and amount')
}
Expand Down Expand Up @@ -256,9 +257,10 @@ function* doWithdrawUSDC({ payload }: ReturnType<typeof beginWithdrawUSDC>) {
)
destinationTokenAccount = destinationTokenAccountPubkey.toString()
}
const amountWei = new BN(amount).mul(
new BN(TOKEN_LISTING_MAP.USDC.decimals)
)
// Multiply by 10^6 to account for USDC decimals, but also convert from cents to dollars
const amountWei = new BN(amount)
.mul(new BN(10 ** TOKEN_LISTING_MAP.USDC.decimals))
.div(new BN(100))
const usdcUserBank = yield* call(getUSDCUserBank)
const transferInstructions = yield* call(
[
Expand Down Expand Up @@ -288,6 +290,8 @@ function* doWithdrawUSDC({ payload }: ReturnType<typeof beginWithdrawUSDC>) {
'Withdraw USDC - successfully transferred USDC - tx hash',
transferSignature
)
yield* call(onSuccess, transferSignature)
yield* put(withdrawUSDCSucceeded())
} catch (e: unknown) {
console.error('Withdraw USDC failed', e)
const reportToSentry = yield* getContext('reportToSentry')
Expand Down
4 changes: 4 additions & 0 deletions packages/web/src/utils/tokenInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ export const onTokenInputBlur = (e: FocusEvent<HTMLInputElement>) => {
.padEnd(PRECISION, '0')
return `${whole.length > 0 ? whole : '0'}.${paddedDecimal}`
}

export const toHumanReadable = (value: number) => {
return (value / 100).toFixed(PRECISION)
}