Skip to content

Commit

Permalink
fix: send send form high fee dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranjamie committed May 7, 2024
1 parent 7a89337 commit a28df65
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 63 deletions.
49 changes: 19 additions & 30 deletions src/app/features/dialogs/high-fee-dialog/high-fee-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import { useEffect, useState } from 'react';

import { useFormikContext } from 'formik';
import { HStack, Stack } from 'leather-styles/jsx';

import {
BitcoinSendFormValues,
StacksSendFormValues,
StacksTransactionFormValues,
} from '@shared/models/form.model';

import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { useStacksCommonSendFormContext } from '@app/pages/send/send-crypto-asset-form/family/stacks/stacks-common-send-form-container';
import { Button } from '@app/ui/components/button/button';
import { Dialog } from '@app/ui/components/containers/dialog/dialog';
import { Footer } from '@app/ui/components/containers/footers/footer';
Expand All @@ -21,36 +14,33 @@ import { ErrorIcon } from '@app/ui/icons';

interface HighFeeDialogProps {
learnMoreUrl: string;
isShowing?: boolean;
}
export function HighFeeDialog({ learnMoreUrl }: HighFeeDialogProps) {
const { handleSubmit, values } = useFormikContext();
const context = useStacksCommonSendFormContext();

export function HighFeeDialog({ learnMoreUrl, isShowing = false }: HighFeeDialogProps) {
const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = useState(isShowing);

useEffect(() => {
return () => {
if (isShowingHighFeeConfirmation) setIsShowingHighFeeConfirmation(false);
};
}, [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation]);

const { handleSubmit, values } = useFormikContext<
BitcoinSendFormValues | StacksSendFormValues | StacksTransactionFormValues
>();
return (
<Dialog
header={<Header variant="dialog" />}
isShowing={isShowingHighFeeConfirmation}
onClose={() => setIsShowingHighFeeConfirmation(false)}
isShowing={context.showHighFeeWarningDialog}
onClose={() => context.setShowHighFeeWarningDialog(false)}
footer={
<Footer flexDirection="row">
<Button
onClick={() => setIsShowingHighFeeConfirmation(false)}
onClick={() => context.setShowHighFeeWarningDialog(false)}
variant="outline"
flexGrow={1}
>
Edit fee
</Button>
<Button onClick={() => handleSubmit()} type="submit" flexGrow={1}>
<Button
onClick={() => {
context.setHasBypassedFeeWarning(true);
handleSubmit();
}}
type="submit"
flexGrow={1}
>
Yes, I'm sure
</Button>
</Footer>
Expand All @@ -60,14 +50,13 @@ export function HighFeeDialog({ learnMoreUrl, isShowing = false }: HighFeeDialog
<HStack>
<ErrorIcon color="red.action-primary-default" width="md" />
<Title>
Are you sure you want to pay {values.fee} {values.feeCurrency} in fees for this
transaction?
Are you sure you want to pay {(values as any).fee} {(values as any).feeCurrency} in fees
for this transaction?
</Title>
</HStack>
<Caption>
This action cannot be undone and the fees won't be returned, even if the transaction
fails.
<Link onClick={() => openInNewTab(learnMoreUrl)} size="sm">
This action cannot be undone. The fees won't be returned, even if the transaction fails.
<Link onClick={() => openInNewTab(learnMoreUrl)} size="sm" ml="space.01">
Learn more
</Link>
</Caption>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useState } from 'react';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';

import { StacksTransaction } from '@stacks/transactions';
Expand Down Expand Up @@ -26,6 +25,7 @@ import { PostConditionModeWarning } from '@app/features/stacks-transaction-reque
import { PostConditions } from '@app/features/stacks-transaction-request/post-conditions/post-conditions';
import { StxTransferDetails } from '@app/features/stacks-transaction-request/stx-transfer-details/stx-transfer-details';
import { TransactionError } from '@app/features/stacks-transaction-request/transaction-error/transaction-error';
import { useStacksCommonSendFormContext } from '@app/pages/send/send-crypto-asset-form/family/stacks/stacks-common-send-form-container';
import { useCurrentStacksAccountBalances } from '@app/query/stacks/balance/stx-balance.hooks';
import { useCalculateStacksTxFees } from '@app/query/stacks/fees/fees.hooks';
import { useNextNonce } from '@app/query/stacks/nonce/account-nonces.hooks';
Expand All @@ -51,15 +51,14 @@ export function StacksTransactionSigner({
onSignStacksTransaction,
isMultisig,
}: StacksTransactionSignerProps) {
const [isShowingHighFeeConfirmation, setIsShowingHighFeeConfirmation] = useState(false);
const transactionRequest = useTransactionRequestState();
const { data: stxFees } = useCalculateStacksTxFees(stacksTransaction);
const analytics = useAnalytics();
const { data: stacksBalances } = useCurrentStacksAccountBalances();
const navigate = useNavigate();
const { data: nextNonce } = useNextNonce();
const { search } = useLocation();

const context = useStacksCommonSendFormContext();
useOnMount(() => {
void analytics.track('view_transaction_signing'), [analytics];
});
Expand Down Expand Up @@ -132,12 +131,9 @@ export function StacksTransactionSigner({
)}
<MinimalErrorMessage />
<SubmitAction
setIsShowingHighFeeConfirmation={() => setIsShowingHighFeeConfirmation(true)}
/>
<HighFeeDialog
isShowing={isShowingHighFeeConfirmation}
learnMoreUrl={HIGH_FEE_WARNING_LEARN_MORE_URL_STX}
setIsShowingHighFeeConfirmation={() => context.showHighFeeWarningDialog(true)}

Check failure on line 134 in src/app/features/stacks-transaction-request/stacks-transaction-signer.tsx

View workflow job for this annotation

GitHub Actions / typecheck

This expression is not callable.
/>
<HighFeeDialog learnMoreUrl={HIGH_FEE_WARNING_LEARN_MORE_URL_STX} />
<Outlet />
</>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createContext, useContext, useState } from 'react';

import type { HasChildren } from '@app/common/has-children';

export interface StacksCommonSendFormContext {
showHighFeeWarningDialog: boolean;
setShowHighFeeWarningDialog(val: boolean): void;
hasBypassedFeeWarning: boolean;
setHasBypassedFeeWarning(val: boolean): void;
}

export const stacksCommonSendFormContext = createContext<StacksCommonSendFormContext | null>(null);

export function useStacksCommonSendFormContext() {
const ctx = useContext(stacksCommonSendFormContext);
if (!ctx) throw new Error(`stacksCommonSendFormContext must be used within a context`);
return ctx;
}

export const StacksCommonSendFormProvider = stacksCommonSendFormContext.Provider;

interface StacksCommonSendFormContainerProps extends HasChildren {}
export function StacksCommonSendFormContainer({ children }: StacksCommonSendFormContainerProps) {
const [showHighFeeWarningDialog, setShowHighFeeWarningDialog] = useState(false);
const [hasBypassedFeeWarning, setHasBypassedFeeWarning] = useState(false);
return (
<StacksCommonSendFormProvider
value={{
showHighFeeWarningDialog,
setShowHighFeeWarningDialog,
hasBypassedFeeWarning,
setHasBypassedFeeWarning,
}}
>
{children}
</StacksCommonSendFormProvider>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BigNumber from 'bignumber.js';
import { FormikHelpers } from 'formik';
import { type FormikErrors, FormikHelpers } from 'formik';

import { HIGH_FEE_AMOUNT_STX } from '@shared/constants';
import { FormErrorMessages } from '@shared/error-messages';
Expand All @@ -17,12 +17,16 @@ import { useCurrentNetworkState } from '@app/store/networks/networks.hooks';

import { useSendFormRouteState } from '../../hooks/use-send-form-route-state';
import { createDefaultInitialFormValues } from '../../send-form.utils';
import { useStacksCommonSendFormContext } from './stacks-common-send-form-container';

function hasHighTxFeeAndNoOtherFormErrors(errors: FormikErrors<unknown>, fee: number | string) {
return isEmpty(errors) && new BigNumber(fee).isGreaterThan(HIGH_FEE_AMOUNT_STX);
}

interface UseStacksCommonSendFormArgs {
symbol: string;
availableTokenBalance: Money;
}

export function useStacksCommonSendForm({
symbol,
availableTokenBalance,
Expand All @@ -31,8 +35,11 @@ export function useStacksCommonSendForm({
const { data: nextNonce } = useNextNonce();
const currentAccountStxAddress = useCurrentAccountStxAddressState();
const currentNetwork = useCurrentNetworkState();
const context = useStacksCommonSendFormContext();

const initialValues: StacksSendFormValues = createDefaultInitialFormValues({
hasDismissedHighFeeWarning: false,
isShowingHighFeeDiaglog: false,
fee: '',
feeCurrency: 'STX',
feeType: FeeTypes[FeeTypes.Unknown],
Expand All @@ -42,13 +49,18 @@ export function useStacksCommonSendForm({
symbol,
...routeState,
});

async function checkFormValidation(
values: StacksSendFormValues,
formikHelpers: FormikHelpers<StacksSendFormValues>
) {
// Validate and check high fee warning first
const formErrors = formikHelpers.validateForm();
if (isEmpty(formErrors) && new BigNumber(values.fee).isGreaterThan(HIGH_FEE_AMOUNT_STX)) {
const formErrors = await formikHelpers.validateForm();

if (
hasHighTxFeeAndNoOtherFormErrors(formErrors, values.fee) &&
!context.hasBypassedFeeWarning
) {
context.setShowHighFeeWarningDialog(true);
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
useGenerateFtTokenTransferUnsignedTx,
} from '@app/store/transactions/token-transfer.hooks';

import { useStacksCommonSendForm } from '../../family/stacks/use-stacks-common-send-form';
import { useSendFormNavigate } from '../../hooks/use-send-form-navigate';
import { useStacksCommonSendForm } from '../stacks/use-stacks-common-send-form';

interface UseSip10SendFormArgs {
symbol: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Outlet, useNavigate } from 'react-router-dom';

import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import BigNumber from 'bignumber.js';
import { Form, Formik, FormikHelpers } from 'formik';
import { Box } from 'leather-styles/jsx';
import { ObjectSchema } from 'yup';

import { HIGH_FEE_AMOUNT_STX, HIGH_FEE_WARNING_LEARN_MORE_URL_STX } from '@shared/constants';
import { HIGH_FEE_WARNING_LEARN_MORE_URL_STX } from '@shared/constants';
import { Fees } from '@shared/models/fees/fees.model';
import { StacksSendFormValues } from '@shared/models/form.model';
import { Money } from '@shared/models/money.model';
Expand Down Expand Up @@ -39,7 +38,6 @@ interface StacksCommonSendFormProps {
selectedAssetField: React.JSX.Element;
availableTokenBalance: Money;
fees?: Fees;
fee?: number | string | BigNumber;
}

export function StacksCommonSendForm({
Expand All @@ -49,7 +47,7 @@ export function StacksCommonSendForm({
amountField,
selectedAssetField,
fees,
fee,

availableTokenBalance,
}: StacksCommonSendFormProps) {
const navigate = useNavigate();
Expand Down Expand Up @@ -100,12 +98,7 @@ export function StacksCommonSendForm({
</CardContent>
</Card>

<HighFeeDialog
isShowing={new BigNumber(fee as BigNumber.Value).isGreaterThan(
HIGH_FEE_AMOUNT_STX
)}
learnMoreUrl={HIGH_FEE_WARNING_LEARN_MORE_URL_STX}
/>
<HighFeeDialog learnMoreUrl={HIGH_FEE_WARNING_LEARN_MORE_URL_STX} />
<Outlet />
</Form>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SendMaxButton } from '../../components/send-max-button';
import { StacksCommonSendForm } from '../stacks/stacks-common-send-form';
import { useStxSendForm } from './use-stx-send-form';

const symbol: CryptoCurrencies = 'STX';
const symbol = 'STX' satisfies CryptoCurrencies;

export function StxSendForm() {
const stxMarketData = useCryptoCurrencyMarketDataMeanAverage(symbol);
Expand All @@ -22,17 +22,16 @@ export function StxSendForm() {
sendMaxBalance,
stxFees: fees,
validationSchema,
fee,
} = useStxSendForm();

const amountField = (
<AmountField
autoComplete="off"
balance={availableStxBalance}
switchableAmount={<SendFiatValue marketData={stxMarketData} assetSymbol={symbol} />}
bottomInputOverlay={
<SendMaxButton balance={availableStxBalance} sendMaxBalance={sendMaxBalance.toString()} />
}
autoComplete="off"
/>
);

Expand All @@ -48,9 +47,6 @@ export function StxSendForm() {
amountField={amountField}
selectedAssetField={selectedAssetField}
fees={fees}
// FIXME 4370 - need to fix this as fee is actually NumberSchema<number | undefined, AnyObject>; in FeeValidatorFactoryArgs
// this needs to be the STX fee so it can be validated against HIGH_FEE_AMOUNT_STX
fee={fee as unknown as string}
availableTokenBalance={availableStxBalance}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {
useStxTokenTransferUnsignedTxState,
} from '@app/store/transactions/token-transfer.hooks';

import { useStacksCommonSendForm } from '../../family/stacks/use-stacks-common-send-form';
import { useSendFormNavigate } from '../../hooks/use-send-form-navigate';
import { useStacksCommonSendForm } from '../stacks/use-stacks-common-send-form';

export function useStxSendForm() {
const unsignedTx = useStxTokenTransferUnsignedTxState();
Expand Down Expand Up @@ -75,7 +75,9 @@ export function useStxSendForm() {
values: StacksSendFormValues,
formikHelpers: FormikHelpers<StacksSendFormValues>
) {
console.log('Submitting the fomr, ', values);

Check failure on line 78 in src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx

View workflow job for this annotation

GitHub Actions / lint-eslint

Unexpected console statement
const isFormValid = await checkFormValidation(values, formikHelpers);
console.log({ isFormValid });

Check failure on line 80 in src/app/pages/send/send-crypto-asset-form/form/stx/use-stx-send-form.tsx

View workflow job for this annotation

GitHub Actions / lint-eslint

Unexpected console statement
if (!isFormValid) return;
const initialFee = values.fee;
values.fee = changeFeeByNonce({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { BtcSentSummary } from '../sent-summary/btc-sent-summary';
import { StxSentSummary } from '../sent-summary/stx-sent-summary';
import { RecipientAccountsDialog } from './components/recipient-accounts-dialog/recipient-accounts-dialog';
import { SendBitcoinAssetContainer } from './family/bitcoin/components/send-bitcoin-asset-container';
import { StacksCommonSendFormContainer } from './family/stacks/stacks-common-send-form-container';
import { Brc20SendForm } from './form/brc-20/brc20-send-form';
import { Brc20SendFormConfirmation } from './form/brc-20/brc20-send-form-confirmation';
import { BrcChooseFee } from './form/brc-20/brc-20-choose-fee';
Expand Down Expand Up @@ -83,7 +84,14 @@ export const sendCryptoAssetFormRoutes = (
<Route path={RouteUrls.SendBrc20Confirmation} element={<Brc20SendFormConfirmation />} />
<Route path={RouteUrls.SentBrc20Summary} element={<Brc20SentSummary />} />
</Route>
<Route path={RouteUrls.SendCryptoAssetForm.replace(':symbol', 'stx')} element={<StxSendForm />}>
<Route
path={RouteUrls.SendCryptoAssetForm.replace(':symbol', 'stx')}
element={
<StacksCommonSendFormContainer>
<StxSendForm />
</StacksCommonSendFormContainer>
}
>
{broadcastErrorDialogRoute}
{editNonceDialogRoute}
{recipientAccountsDialogRoute}
Expand All @@ -94,7 +102,14 @@ export const sendCryptoAssetFormRoutes = (
>
{ledgerStacksTxSigningRoutes}
</Route>
<Route path={RouteUrls.SendSip10Form} element={<Sip10TokenSendForm />}>
<Route
path={RouteUrls.SendSip10Form}
element={
<StacksCommonSendFormContainer>
<Sip10TokenSendForm />
</StacksCommonSendFormContainer>
}
>
{broadcastErrorDialogRoute}
{editNonceDialogRoute}
{recipientAccountsDialogRoute}
Expand Down

0 comments on commit a28df65

Please sign in to comment.