Skip to content

Commit fe6c771

Browse files
authoredFeb 28, 2025··
Remove "Review transaction" view (#3164)
* Remove Review Tx view Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Remove unused param from useGasSlider Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Refactor Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Disable/dim all actionable components when tx in progress Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Disable widget when tx in progress Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Replace invalid clickEvent CSS props with pointerEvents Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Fix gas slider thumb glitch when expanding collapsible container Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Fix eslint warnings Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Fix old token config references Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Add missing dispatches Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Fix lint errors Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Fix naming Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Update gas top-up control Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Revert "Update gas top-up control" This reverts commit f4aff98. * Slider styling Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> * Refactor Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz> --------- Signed-off-by: Emre Bogazliyanlioglu <emre@wormholelabs.xyz>
1 parent 9f908fc commit fe6c771

File tree

15 files changed

+441
-453
lines changed

15 files changed

+441
-453
lines changed
 

‎wormhole-connect/src/components/Button.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const useStyles = makeStyles()((theme: any) => ({
1717
},
1818
disabled: {
1919
cursor: 'not-allowed',
20-
clickEvents: 'none',
20+
pointerEvents: 'none',
2121
backgroundColor: theme.palette.button.disabled + ' !important',
2222
color: theme.palette.button.disabledText + ' !important',
2323
},
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
1-
import React, { useContext, useMemo, useState } from 'react';
1+
import { useContext, useState } from 'react';
22
import { useDispatch, useSelector } from 'react-redux';
3-
import { makeStyles } from 'tss-react/mui';
4-
import { useMediaQuery, useTheme } from '@mui/material';
5-
import CircularProgress from '@mui/material/CircularProgress';
6-
import Collapse from '@mui/material/Collapse';
7-
import Stack from '@mui/material/Stack';
8-
import Typography from '@mui/material/Typography';
9-
import ChevronLeft from '@mui/icons-material/ChevronLeft';
10-
import IconButton from '@mui/material/IconButton';
11-
import { getTransferDetails } from 'telemetry';
123
import { Context } from 'sdklegacy';
134

14-
import Button from 'components/v2/Button';
155
import config from 'config';
16-
import { addTxToLocalStorage } from 'utils/inProgressTxCache';
176
import { RouteContext } from 'contexts/RouteContext';
18-
import { useGasSlider } from 'hooks/useGasSlider';
7+
import { useUSDamountGetter } from 'hooks/useUSDamountGetter';
8+
import { useGetTokens } from 'hooks/useGetTokens';
199
import {
2010
setTxDetails,
2111
setSendTx,
@@ -24,57 +14,41 @@ import {
2414
} from 'store/redeem';
2515
import { setRoute as setAppRoute } from 'store/router';
2616
import { setAmount, setIsTransactionInProgress } from 'store/transferInput';
27-
import { getWrappedToken } from 'utils';
17+
import { getTransferDetails } from 'telemetry';
18+
import { ERR_USER_REJECTED } from 'telemetry/types';
19+
import { toDecimals } from 'utils/balance';
2820
import { interpretTransferError } from 'utils/errors';
21+
import { addTxToLocalStorage } from 'utils/inProgressTxCache';
2922
import { validate, isTransferValid } from 'utils/transferValidation';
3023
import {
3124
registerWalletSigner,
3225
switchChain,
3326
TransferWallet,
3427
} from 'utils/wallet';
35-
import GasSlider from 'views/v2/Bridge/ReviewTransaction/GasSlider';
36-
import SingleRoute from 'views/v2/Bridge/Routes/SingleRoute';
3728

3829
import type { RootState } from 'store';
39-
import { RelayerFee } from 'store/relay';
40-
41-
import { amount as sdkAmount } from '@wormhole-foundation/sdk';
42-
import { toDecimals } from 'utils/balance';
43-
import { useUSDamountGetter } from 'hooks/useUSDamountGetter';
44-
import SendError from './SendError';
45-
import { ERR_USER_REJECTED } from 'telemetry/types';
46-
import { useGetTokens } from 'hooks/useGetTokens';
47-
48-
const useStyles = makeStyles()((theme) => ({
49-
container: {
50-
gap: '16px',
51-
width: '100%',
52-
maxWidth: '420px',
53-
},
54-
confirmTransaction: {
55-
padding: '8px 16px',
56-
borderRadius: '8px',
57-
margin: 'auto',
58-
maxWidth: '420px',
59-
width: '100%',
60-
},
61-
}));
30+
import type { RelayerFee } from 'store/relay';
31+
import type { QuoteResult } from 'routes/operator';
6232

6333
type Props = {
64-
onClose: () => void;
65-
quotes: any;
66-
isFetchingQuotes: boolean;
34+
quotes: Record<string, QuoteResult | undefined>;
6735
};
6836

69-
const ReviewTransaction = (props: Props) => {
70-
const { classes } = useStyles();
71-
const dispatch = useDispatch();
72-
const theme = useTheme();
37+
type ReturnProps = {
38+
error: string | undefined;
39+
// errorInternal can be a result of custom validation, hence of any type.
40+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
41+
errorInternal: any | undefined;
42+
onConfirm: () => void;
43+
};
7344

74-
const mobile = useMediaQuery(theme.breakpoints.down('sm'));
45+
const useConfirmTransaction = (props: Props): ReturnProps => {
46+
const dispatch = useDispatch();
7547

76-
const [sendError, setSendError] = useState<string | undefined>(undefined);
77-
const [sendErrorInternal, setSendErrorInternal] = useState<any | undefined>(
48+
const [error, setError] = useState<string | undefined>(undefined);
49+
// errorInternal can be a result of custom validation, hence of any type.
50+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
51+
const [errorInternal, setErrorInternal] = useState<any | undefined>(
7852
undefined,
7953
);
8054

@@ -86,39 +60,32 @@ const ReviewTransaction = (props: Props) => {
8660
amount,
8761
fromChain: sourceChain,
8862
toChain: destChain,
89-
isTransactionInProgress,
9063
route,
9164
validations,
9265
} = transferInput;
9366

67+
const { sourceToken, destToken } = useGetTokens();
68+
9469
const wallet = useSelector((state: RootState) => state.wallet);
9570
const { sending: sendingWallet, receiving: receivingWallet } = wallet;
9671

9772
const relay = useSelector((state: RootState) => state.relay);
9873
const { toNativeToken } = relay;
9974

100-
const getUSDAmount = useUSDamountGetter();
101-
102-
const { sourceToken, destToken } = useGetTokens();
103-
104-
const { disabled: isGasSliderDisabled, showGasSlider } = useGasSlider({
105-
destChain,
106-
destToken: destToken!.key,
107-
route,
108-
valid: true,
109-
isTransactionInProgress,
110-
});
111-
11275
const quoteResult = props.quotes[route ?? ''];
11376
const quote = quoteResult?.success ? quoteResult : undefined;
114-
11577
const receiveNativeAmount = quote?.destinationNativeGas;
11678

117-
const send = async () => {
118-
setSendError(undefined);
79+
const getUSDAmount = useUSDamountGetter();
80+
81+
const onConfirm = async () => {
82+
// Clear previous errors
83+
if (error) {
84+
setError(undefined);
85+
}
11986

12087
if (config.ui.previewMode) {
121-
setSendError('Connect is in preview mode');
88+
setError('Connect is in preview mode');
12289
return;
12390
}
12491

@@ -135,6 +102,8 @@ const ReviewTransaction = (props: Props) => {
135102
return;
136103
}
137104

105+
// Validate all inputs
106+
// The results of this check will be written back to Redux store (see transferInput.validations).
138107
await validate({ transferInput, relay, wallet }, dispatch, () => false);
139108

140109
const valid = isTransferValid(validations);
@@ -162,12 +131,12 @@ const ReviewTransaction = (props: Props) => {
162131
toWalletAddress: receivingWallet.address,
163132
});
164133
if (!isValid) {
165-
setSendError(error ?? 'Transfer validation failed');
134+
setError(error ?? 'Transfer validation failed');
166135
return;
167136
}
168-
} catch (e) {
169-
setSendError('Error validating transfer');
170-
setSendErrorInternal(e);
137+
} catch (e: unknown) {
138+
setError('Error validating transfer');
139+
setErrorInternal(e);
171140
console.error(e);
172141
return;
173142
}
@@ -176,7 +145,7 @@ const ReviewTransaction = (props: Props) => {
176145
dispatch(setIsTransactionInProgress(true));
177146

178147
try {
179-
const fromConfig = config.chains[sourceChain!];
148+
const fromConfig = config.chains[sourceChain];
180149

181150
if (fromConfig?.context === Context.ETH) {
182151
const chainId = fromConfig.chainId;
@@ -242,10 +211,11 @@ const ReviewTransaction = (props: Props) => {
242211
recipient: receivingWallet.address,
243212
toChain: receipt.to,
244213
fromChain: receipt.from,
245-
tokenAddress: getWrappedToken(sourceToken).tokenId!.address.toString(),
214+
receivedToken: destToken.tuple,
246215
token: sourceToken.tuple,
216+
tokenAddress: sourceToken.tuple[1],
217+
tokenKey: sourceToken.key,
247218
tokenDecimals: sourceToken.decimals,
248-
receivedToken: destToken.tuple, // TODO: possibly wrong (e..g if portico swap fails)
249219
relayerFee,
250220
receiveAmount: quote.destinationToken.amount,
251221
receiveNativeAmount,
@@ -280,8 +250,8 @@ const ReviewTransaction = (props: Props) => {
280250
dispatch(setSendTx(txId));
281251
dispatch(setRedeemRoute(route));
282252
dispatch(setAppRoute('redeem'));
283-
setSendError(undefined);
284-
} catch (e: any) {
253+
setError(undefined);
254+
} catch (e: unknown) {
285255
const [uiError, transferError] = interpretTransferError(
286256
e,
287257
transferDetails,
@@ -294,8 +264,8 @@ const ReviewTransaction = (props: Props) => {
294264
console.error('Wormhole Connect: error completing transfer', e);
295265

296266
// Show error in UI
297-
setSendError(uiError);
298-
setSendErrorInternal(e);
267+
setError(uiError);
268+
setErrorInternal(e);
299269

300270
// Trigger transfer error event to integrator
301271
config.triggerEvent({
@@ -309,108 +279,11 @@ const ReviewTransaction = (props: Props) => {
309279
}
310280
};
311281

312-
const walletsConnected = useMemo(
313-
() => !!sendingWallet.address && !!receivingWallet.address,
314-
[sendingWallet.address, receivingWallet.address],
315-
);
316-
317-
// Review transaction button is shown only when everything is ready
318-
const confirmTransactionButton = useMemo(() => {
319-
if (
320-
!sourceChain ||
321-
!sourceToken ||
322-
!destChain ||
323-
!destToken ||
324-
!route ||
325-
!amount
326-
) {
327-
return null;
328-
}
329-
330-
return (
331-
<Button
332-
disabled={props.isFetchingQuotes || isTransactionInProgress}
333-
variant="primary"
334-
className={classes.confirmTransaction}
335-
onClick={() => send()}
336-
>
337-
{isTransactionInProgress ? (
338-
<Typography
339-
display="flex"
340-
alignItems="center"
341-
gap={1}
342-
textTransform="none"
343-
>
344-
<CircularProgress
345-
size={16}
346-
sx={{ color: theme.palette.primary.contrastText }}
347-
/>
348-
{mobile ? 'Preparing' : 'Preparing transaction'}
349-
</Typography>
350-
) : !isTransactionInProgress && props.isFetchingQuotes ? (
351-
<Typography
352-
display="flex"
353-
alignItems="center"
354-
gap={1}
355-
textTransform="none"
356-
>
357-
<CircularProgress color="secondary" size={16} />
358-
{mobile ? 'Refreshing' : 'Refreshing quote'}
359-
</Typography>
360-
) : (
361-
<Typography textTransform="none">
362-
{mobile ? 'Confirm' : 'Confirm transaction'}
363-
</Typography>
364-
)}
365-
</Button>
366-
);
367-
}, [
368-
props.isFetchingQuotes,
369-
isTransactionInProgress,
370-
sourceChain,
371-
sourceToken,
372-
destChain,
373-
destToken,
374-
route,
375-
amount,
376-
send,
377-
]);
378-
379-
if (!route || !walletsConnected) {
380-
return <></>;
381-
}
382-
383-
return (
384-
<Stack className={classes.container}>
385-
<div>
386-
<IconButton
387-
disabled={isTransactionInProgress}
388-
sx={{ padding: 0 }}
389-
onClick={() => props.onClose?.()}
390-
>
391-
<ChevronLeft sx={{ fontSize: '32px' }} />
392-
</IconButton>
393-
</div>
394-
<SingleRoute
395-
route={route}
396-
isSelected={true}
397-
destinationGasDrop={receiveNativeAmount}
398-
quote={quote}
399-
/>
400-
{showGasSlider && (
401-
<Collapse in={showGasSlider}>
402-
<GasSlider
403-
destinationGasDrop={
404-
receiveNativeAmount || sdkAmount.fromBaseUnits(0n, 8)
405-
}
406-
disabled={isGasSliderDisabled}
407-
/>
408-
</Collapse>
409-
)}
410-
<SendError humanError={sendError} internalError={sendErrorInternal} />
411-
{confirmTransactionButton}
412-
</Stack>
413-
);
282+
return {
283+
onConfirm,
284+
error,
285+
errorInternal,
286+
};
414287
};
415288

416-
export default ReviewTransaction;
289+
export default useConfirmTransaction;

‎wormhole-connect/src/hooks/useGasSlider.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import { Chain } from '@wormhole-foundation/sdk';
55

66
type Props = {
77
destChain: Chain | undefined;
8-
destToken: string;
8+
destToken: string | undefined;
99
route?: string;
10-
valid: boolean;
1110
isTransactionInProgress: boolean;
1211
};
1312

@@ -17,9 +16,9 @@ export const useGasSlider = (
1716
disabled: boolean;
1817
showGasSlider: boolean | undefined;
1918
} => {
20-
const { destChain, destToken, route, isTransactionInProgress, valid } = props;
19+
const { destChain, destToken, route, isTransactionInProgress } = props;
2120

22-
const disabled = !valid || isTransactionInProgress;
21+
const disabled = isTransactionInProgress;
2322
const toChainConfig = destChain ? config.chains[destChain] : undefined;
2423
const gasTokenConfig = toChainConfig
2524
? config.tokens.getGasToken(toChainConfig.sdkName)

0 commit comments

Comments
 (0)
Please sign in to comment.