From 17bd98867f2fdb26644502a31bc6394566a59f86 Mon Sep 17 00:00:00 2001 From: Petr Knetl Date: Mon, 30 Sep 2024 09:04:11 +0200 Subject: [PATCH] feat(suite-native): send flow handles device disconect during a review --- .../src/send/sendFormBitcoinThunks.ts | 2 +- .../src/send/sendFormCardanoThunks.ts | 2 +- .../src/send/sendFormEthereumThunks.ts | 2 +- .../src/send/sendFormRippleThunks.ts | 2 +- .../src/send/sendFormSolanaThunks.ts | 2 +- .../wallet-core/src/send/sendFormTypes.ts | 3 +- .../src/hooks/useHandleDeviceConnection.ts | 23 ++++- suite-native/intl/src/en.ts | 5 + .../connect/ConnectDeviceScreenHeader.tsx | 2 +- .../connect/ConnectAndUnlockDeviceScreen.tsx | 6 +- suite-native/module-send/package.json | 3 +- .../src/components/AddressReviewStepList.tsx | 41 ++------ .../src/components/SendFeesForm.tsx | 14 ++- .../src/hooks/useHandleSendReviewFailure.tsx | 95 +++++++++++++++++++ .../hooks/useShowDeviceDisconnectedAlert.tsx | 71 ++++++++++++++ .../src/screens/SendAddressReviewScreen.tsx | 3 + .../module-send/src/sendOutputsFormSchema.ts | 2 +- suite-native/module-send/tsconfig.json | 5 +- suite-native/navigation/src/types.tsx | 2 +- yarn.lock | 3 +- 20 files changed, 230 insertions(+), 58 deletions(-) create mode 100644 suite-native/module-send/src/hooks/useHandleSendReviewFailure.tsx create mode 100644 suite-native/module-send/src/hooks/useShowDeviceDisconnectedAlert.tsx diff --git a/suite-common/wallet-core/src/send/sendFormBitcoinThunks.ts b/suite-common/wallet-core/src/send/sendFormBitcoinThunks.ts index fa4c3335ac7..d863fd90c2f 100644 --- a/suite-common/wallet-core/src/send/sendFormBitcoinThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormBitcoinThunks.ts @@ -341,7 +341,7 @@ export const signBitcoinSendFormTransactionThunk = createThunk< if (!response.success) { return rejectWithValue({ error: 'sign-transaction-failed', - connectErrorCode: response.payload.code, + errorCode: response.payload.code, message: response.payload.error, }); } diff --git a/suite-common/wallet-core/src/send/sendFormCardanoThunks.ts b/suite-common/wallet-core/src/send/sendFormCardanoThunks.ts index 984ade81db7..d8c386665f6 100644 --- a/suite-common/wallet-core/src/send/sendFormCardanoThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormCardanoThunks.ts @@ -178,7 +178,7 @@ export const signCardanoSendFormTransactionThunk = createThunk< if (!response.success) { return rejectWithValue({ error: 'sign-transaction-failed', - connectErrorCode: response.payload.code, + errorCode: response.payload.code, message: response.payload.error, }); } diff --git a/suite-common/wallet-core/src/send/sendFormEthereumThunks.ts b/suite-common/wallet-core/src/send/sendFormEthereumThunks.ts index 2de5bffdb84..e64eaa668b2 100644 --- a/suite-common/wallet-core/src/send/sendFormEthereumThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormEthereumThunks.ts @@ -302,7 +302,7 @@ export const signEthereumSendFormTransactionThunk = createThunk< // catch manual error from TransactionReviewModal return rejectWithValue({ error: 'sign-transaction-failed', - connectErrorCode: response.payload.code, + errorCode: response.payload.code, message: response.payload.error, }); } diff --git a/suite-common/wallet-core/src/send/sendFormRippleThunks.ts b/suite-common/wallet-core/src/send/sendFormRippleThunks.ts index 59727927feb..4be4d464126 100644 --- a/suite-common/wallet-core/src/send/sendFormRippleThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormRippleThunks.ts @@ -241,7 +241,7 @@ export const signRippleSendFormTransactionThunk = createThunk< // catch manual error from TransactionReviewModal return rejectWithValue({ error: 'sign-transaction-failed', - connectErrorCode: response.payload.code, + errorCode: response.payload.code, message: response.payload.error, }); } diff --git a/suite-common/wallet-core/src/send/sendFormSolanaThunks.ts b/suite-common/wallet-core/src/send/sendFormSolanaThunks.ts index 0ac45c905c1..8d04f641642 100644 --- a/suite-common/wallet-core/src/send/sendFormSolanaThunks.ts +++ b/suite-common/wallet-core/src/send/sendFormSolanaThunks.ts @@ -404,7 +404,7 @@ export const signSolanaSendFormTransactionThunk = createThunk< // catch manual error from TransactionReviewModal return rejectWithValue({ error: 'sign-transaction-failed', - connectErrorCode: response.payload.code, + errorCode: response.payload.code, message: response.payload.error, }); } diff --git a/suite-common/wallet-core/src/send/sendFormTypes.ts b/suite-common/wallet-core/src/send/sendFormTypes.ts index e9bbd14bfff..e979c8a7347 100644 --- a/suite-common/wallet-core/src/send/sendFormTypes.ts +++ b/suite-common/wallet-core/src/send/sendFormTypes.ts @@ -9,6 +9,7 @@ import { import { TokenInfo, Unsuccessful } from '@trezor/connect'; import { Network, NetworkSymbol } from '@suite-common/wallet-config'; import { TrezorDevice } from '@suite-common/suite-types'; +import { ERRORS as CONNECT_ERRORS } from '@trezor/connect'; export type SerializedTx = { tx: string; coin: NetworkSymbol }; @@ -53,7 +54,7 @@ export type ComposeFeeLevelsError = { export type SignTransactionError = { error: 'sign-transaction-failed'; - connectErrorCode?: string; + errorCode?: CONNECT_ERRORS.ErrorCode; message?: string; }; diff --git a/suite-native/device/src/hooks/useHandleDeviceConnection.ts b/suite-native/device/src/hooks/useHandleDeviceConnection.ts index c535735b6fb..0938b926707 100644 --- a/suite-native/device/src/hooks/useHandleDeviceConnection.ts +++ b/suite-native/device/src/hooks/useHandleDeviceConnection.ts @@ -19,6 +19,7 @@ import { selectIsNoPhysicalDeviceConnected, selectIsDeviceUsingPassphrase, authorizeDeviceThunk, + selectIsDeviceRemembered, } from '@suite-common/wallet-core'; import { selectDeviceRequestedPin } from '@suite-native/device-authorization'; import { selectIsOnboardingFinished } from '@suite-native/settings'; @@ -35,6 +36,7 @@ export const useHandleDeviceConnection = () => { const isNoPhysicalDeviceConnected = useSelector(selectIsNoPhysicalDeviceConnected); const isPortfolioTrackerDevice = useSelector(selectIsPortfolioTrackerDevice); const isOnboardingFinished = useSelector(selectIsOnboardingFinished); + const isDeviceRemembered = useSelector(selectIsDeviceRemembered); const isDeviceConnectedAndAuthorized = useSelector(selectIsDeviceConnectedAndAuthorized); const hasDeviceRequestedPin = useSelector(selectDeviceRequestedPin); const isDeviceConnected = useSelector(selectIsDeviceConnected); @@ -43,6 +45,10 @@ export const useHandleDeviceConnection = () => { const navigation = useNavigation(); const dispatch = useDispatch(); + const isSendStackFocused = + navigation.getState()?.routes.at(-1)?.name === RootStackRoutes.SendStack; + const shouldBlockSendReviewRedirect = isDeviceRemembered && isSendStackFocused; + // At the moment when unauthorized physical device is selected, // redirect to the Connecting screen where is handled the connection logic. useEffect(() => { @@ -59,7 +65,7 @@ export const useHandleDeviceConnection = () => { // Note: Passphrase protected device (excluding empty passphrase, e. g. standard wallet with passphrase protection on device), // post auth navigation is handled in @suite-native/module-passphrase for custom UX flow. - if (!isDeviceUsingPassphrase) { + if (!isDeviceUsingPassphrase && !shouldBlockSendReviewRedirect) { navigation.navigate(RootStackRoutes.AuthorizeDeviceStack, { screen: AuthorizeDeviceStackRoutes.ConnectingDevice, }); @@ -75,17 +81,19 @@ export const useHandleDeviceConnection = () => { isBiometricsOverlayVisible, navigation, isDeviceUsingPassphrase, + shouldBlockSendReviewRedirect, ]); // In case that the physical device is disconnected, redirect to the home screen and // set connecting screen to be displayed again on the next device connection. useEffect(() => { if (isNoPhysicalDeviceConnected && isOnboardingFinished) { + const previousRoute = navigation.getState()?.routes.at(-1)?.name; + // This accidentally gets triggered by finishing onboarding with no device connected, // so this prevents from redirect being duplicated. - const isPreviousRouteOnboarding = - navigation.getState()?.routes.at(-1)?.name === RootStackRoutes.Onboarding; - if (isPreviousRouteOnboarding) { + const isPreviousRouteOnboarding = previousRoute === RootStackRoutes.Onboarding; + if (isPreviousRouteOnboarding || shouldBlockSendReviewRedirect) { return; } navigation.navigate(RootStackRoutes.AppTabs, { @@ -95,7 +103,12 @@ export const useHandleDeviceConnection = () => { }, }); } - }, [isNoPhysicalDeviceConnected, isOnboardingFinished, navigation]); + }, [ + isNoPhysicalDeviceConnected, + isOnboardingFinished, + navigation, + shouldBlockSendReviewRedirect, + ]); // When trezor gets locked, it is necessary to display a PIN matrix for T1 so that it can be unlocked // and then continue with the interaction. For T2, PIN is entered on device, but the screen is still displayed. diff --git a/suite-native/intl/src/en.ts b/suite-native/intl/src/en.ts index 22979470bbc..505001b46fe 100644 --- a/suite-native/intl/src/en.ts +++ b/suite-native/intl/src/en.ts @@ -903,6 +903,11 @@ export const en = { title: 'Are you sure you’d like to cancel sending the transaction?', continueButton: 'Continue editing', }, + deviceDisconnectedAlert: { + title: 'Your Trezor has been disconnected.', + description: 'Reconnect your Trezor to continue.', + primaryButton: 'Reconnect Trezor', + }, lockedToast: 'Device is locked.', address: { title: 'Check the address on your Trezor against the original to make sure it’s correct.', diff --git a/suite-native/module-authorize-device/src/components/connect/ConnectDeviceScreenHeader.tsx b/suite-native/module-authorize-device/src/components/connect/ConnectDeviceScreenHeader.tsx index 70df952605d..e4b461366de 100644 --- a/suite-native/module-authorize-device/src/components/connect/ConnectDeviceScreenHeader.tsx +++ b/suite-native/module-authorize-device/src/components/connect/ConnectDeviceScreenHeader.tsx @@ -73,7 +73,7 @@ export const ConnectDeviceScreenHeader = ({ } if (onCancelNavigationTarget) { - navigation.navigate(...onCancelNavigationTarget); + navigation.navigate(onCancelNavigationTarget); return; } diff --git a/suite-native/module-authorize-device/src/screens/connect/ConnectAndUnlockDeviceScreen.tsx b/suite-native/module-authorize-device/src/screens/connect/ConnectAndUnlockDeviceScreen.tsx index bf7c89777b6..5a9dba288b4 100644 --- a/suite-native/module-authorize-device/src/screens/connect/ConnectAndUnlockDeviceScreen.tsx +++ b/suite-native/module-authorize-device/src/screens/connect/ConnectAndUnlockDeviceScreen.tsx @@ -74,7 +74,11 @@ export const ConnectAndUnlockDeviceScreen = ({ return ( } + screenHeader={ + + } customHorizontalPadding={0} customVerticalPadding={0} hasBottomInset={false} diff --git a/suite-native/module-send/package.json b/suite-native/module-send/package.json index 1f2a9fc835f..2c518606a5a 100644 --- a/suite-native/module-send/package.json +++ b/suite-native/module-send/package.json @@ -37,11 +37,12 @@ "@suite-native/navigation": "workspace:*", "@suite-native/qr-code": "workspace:*", "@suite-native/settings": "workspace:*", - "@suite-native/toasts": "workspace:*", "@trezor/blockchain-link-types": "workspace:*", "@trezor/react-utils": "workspace:*", "@trezor/styles": "workspace:*", "@trezor/theme": "workspace:*", + "@trezor/transport": "workspace:*", + "@trezor/utils": "workspace:*", "expo-linear-gradient": "13.0.2", "react": "18.2.0", "react-hook-form": "^7.53.0", diff --git a/suite-native/module-send/src/components/AddressReviewStepList.tsx b/suite-native/module-send/src/components/AddressReviewStepList.tsx index 4e0636b4366..fd2cbb6559d 100644 --- a/suite-native/module-send/src/components/AddressReviewStepList.tsx +++ b/suite-native/module-send/src/components/AddressReviewStepList.tsx @@ -7,7 +7,6 @@ import { useNavigation, useRoute } from '@react-navigation/native'; import { RootStackParamList, - RootStackRoutes, SendStackParamList, SendStackRoutes, StackProps, @@ -17,7 +16,6 @@ import { Button, VStack } from '@suite-native/atoms'; import { Translation } from '@suite-native/intl'; import { AccountsRootState, DeviceRootState, SendRootState } from '@suite-common/wallet-core'; import { nativeSpacings } from '@trezor/theme'; -import { useToast } from '@suite-native/toasts'; import { cleanupSendFormThunk, @@ -28,6 +26,7 @@ import { SlidingFooterOverlay } from '../components/SlidingFooterOverlay'; import { AddressReviewStep } from '../components/AddressReviewStep'; import { CompareAddressHelpButton } from '../components/CompareAddressHelpButton'; import { AddressOriginHelpButton } from '../components/AddressOriginHelpButton'; +import { useHandleSendReviewFailure } from '../hooks/useHandleSendReviewFailure'; const NUMBER_OF_STEPS = 3; const OVERLAY_INITIAL_POSITION = 75; @@ -42,16 +41,16 @@ type NavigationProps = StackToStackCompositeNavigationProps< export const AddressReviewStepList = () => { const route = useRoute(); + const { accountKey, transaction } = route.params; const navigation = useNavigation(); const dispatch = useDispatch(); const [childHeights, setChildHeights] = useState([]); const [stepIndex, setStepIndex] = useState(0); - const { showToast } = useToast(); + const handleSendReviewFailure = useHandleSendReviewFailure({ accountKey, transaction }); const areAllStepsDone = stepIndex === NUMBER_OF_STEPS - 1; const isLayoutReady = childHeights.length === NUMBER_OF_STEPS; - const { accountKey, transaction } = route.params; const isAddressConfirmed = useSelector( (state: AccountsRootState & DeviceRootState & SendRootState) => @@ -74,6 +73,11 @@ export const AddressReviewStepList = () => { }); }; + const restartAddressReview = () => { + setStepIndex(0); + dispatch(cleanupSendFormThunk({ accountKey, shouldDeleteDraft: false })); + }; + const handleNextStep = async () => { setStepIndex(prevStepIndex => prevStepIndex + 1); @@ -86,33 +90,8 @@ export const AddressReviewStepList = () => { ); if (isRejected(response)) { - const connectErrorCode = response.payload?.connectErrorCode; - // In case that the signing review is interrupted, restart the flow so user can try again. - if ( - connectErrorCode === 'Failure_PinCancelled' || // User cancelled the pin entry on device - connectErrorCode === 'Method_Cancel' || // User canceled the pin entry in the app UI. - connectErrorCode === 'Failure_ActionCancelled' // Device got locked before the review was finished. - ) { - showToast({ - message: , - variant: 'error', - icon: 'closeCircle', - }); - navigation.navigate(SendStackRoutes.SendAddressReview, { - accountKey, - transaction, - }); - setStepIndex(0); - dispatch(cleanupSendFormThunk({ accountKey, shouldDeleteDraft: false })); - - return; - } - - // Review was exited or cancelled on purpose. - navigation.navigate(RootStackRoutes.AccountDetail, { - accountKey, - closeActionType: 'back', - }); + restartAddressReview(); + handleSendReviewFailure(response); } } }; diff --git a/suite-native/module-send/src/components/SendFeesForm.tsx b/suite-native/module-send/src/components/SendFeesForm.tsx index 48887cd66d5..9c26699484d 100644 --- a/suite-native/module-send/src/components/SendFeesForm.tsx +++ b/suite-native/module-send/src/components/SendFeesForm.tsx @@ -78,15 +78,13 @@ export const SendFeesForm = ({ accountKey, feeLevels }: SendFormProps) => { screen: AuthorizeDeviceStackRoutes.ConnectAndUnlockDevice, params: { // If user cancels, navigate back to the send fees screen. - onCancelNavigationTarget: [ - { - name: RootStackRoutes.SendStack, - params: { - screen: SendStackRoutes.SendFees, - params: { accountKey, feeLevels }, - }, + onCancelNavigationTarget: { + name: RootStackRoutes.SendStack, + params: { + screen: SendStackRoutes.SendFees, + params: { accountKey, feeLevels }, }, - ], + }, }, }); }); diff --git a/suite-native/module-send/src/hooks/useHandleSendReviewFailure.tsx b/suite-native/module-send/src/hooks/useHandleSendReviewFailure.tsx new file mode 100644 index 00000000000..a4061164ed3 --- /dev/null +++ b/suite-native/module-send/src/hooks/useHandleSendReviewFailure.tsx @@ -0,0 +1,95 @@ +import { useSelector } from 'react-redux'; + +import { useNavigation } from '@react-navigation/native'; +import { PayloadAction } from '@reduxjs/toolkit'; + +import { Translation } from '@suite-native/intl'; +import { useAlert } from '@suite-native/alerts'; +import { selectIsDeviceRemembered, SignTransactionError } from '@suite-common/wallet-core'; +import { + RootStackParamList, + RootStackRoutes, + SendStackParamList, + SendStackRoutes, + StackToStackCompositeNavigationProps, +} from '@suite-native/navigation'; +import { GeneralPrecomposedTransactionFinal } from '@suite-common/wallet-types'; +import { TRANSPORT_ERROR } from '@trezor/transport'; + +import { useShowDeviceDisconnectedAlert } from './useShowDeviceDisconnectedAlert'; + +type NavigationProps = StackToStackCompositeNavigationProps< + SendStackParamList, + SendStackRoutes.SendOutputsReview, + RootStackParamList +>; + +type UseHandleSendReviewFailureArguments = { + accountKey: string; + transaction: GeneralPrecomposedTransactionFinal; +}; + +export const useHandleSendReviewFailure = ({ + accountKey, + transaction, +}: UseHandleSendReviewFailureArguments) => { + const navigation = useNavigation(); + const { showAlert } = useAlert(); + const isViewOnlyDevice = useSelector(selectIsDeviceRemembered); + const showDeviceDisconnectedAlert = useShowDeviceDisconnectedAlert(); + + const handleSendReviewFailure = (response: PayloadAction) => { + const errorCode = response.payload?.errorCode; + const message = response.payload?.message; + + if ( + errorCode === 'Failure_PinCancelled' || // User cancelled the pin entry on device + errorCode === 'Method_Cancel' || // User canceled the pin entry in the app UI. + errorCode === 'Failure_ActionCancelled' // User canceled the review on device OR device got locked before the review was finished. + ) { + navigation.navigate(SendStackRoutes.SendAddressReview, { + accountKey, + transaction, + }); + + return; + } + + if ( + errorCode === 'Device_InvalidState' || // Incorrect Passphrase submitted. + errorCode === 'Method_Interrupted' // Passphrase modal closed. + ) { + showAlert({ + title: , + pictogramVariant: 'red', + primaryButtonTitle: , + primaryButtonVariant: 'redBold', + }); + + return; + } + + // Device disconnected during the review. + if ( + message === TRANSPORT_ERROR.DEVICE_DISCONNECTED_DURING_ACTION || + message === TRANSPORT_ERROR.UNEXPECTED_ERROR + ) { + if (isViewOnlyDevice) { + navigation.navigate(SendStackRoutes.SendAddressReview, { + accountKey, + transaction, + }); + } + showDeviceDisconnectedAlert(); + + return; + } + + navigation.navigate(RootStackRoutes.AccountDetail, { + accountKey, + closeActionType: 'back', + }); + }; + + return handleSendReviewFailure; +}; diff --git a/suite-native/module-send/src/hooks/useShowDeviceDisconnectedAlert.tsx b/suite-native/module-send/src/hooks/useShowDeviceDisconnectedAlert.tsx new file mode 100644 index 00000000000..591a8890c0e --- /dev/null +++ b/suite-native/module-send/src/hooks/useShowDeviceDisconnectedAlert.tsx @@ -0,0 +1,71 @@ +import { useNavigation } from '@react-navigation/native'; + +import { useAlert } from '@suite-native/alerts'; +import { Translation } from '@suite-native/intl'; +import { + StackToStackCompositeNavigationProps, + SendStackParamList, + SendStackRoutes, + RootStackParamList, + RootStackRoutes, + AppTabsRoutes, + HomeStackRoutes, + AuthorizeDeviceStackRoutes, +} from '@suite-native/navigation'; + +type NavigationProps = StackToStackCompositeNavigationProps< + SendStackParamList, + SendStackRoutes.SendOutputsReview, + RootStackParamList +>; + +export const useShowDeviceDisconnectedAlert = () => { + const { showAlert } = useAlert(); + const navigation = useNavigation(); + + const handleReconnect = () => { + navigation.navigate(RootStackRoutes.AuthorizeDeviceStack, { + screen: AuthorizeDeviceStackRoutes.ConnectAndUnlockDevice, + params: { + // If user cancels the re-connecting process, redirect him to the Home screen. + onCancelNavigationTarget: { + name: RootStackRoutes.AppTabs, + params: { + screen: AppTabsRoutes.HomeStack, + params: { screen: HomeStackRoutes.Home }, + }, + }, + }, + }); + }; + + const handleCancel = () => { + navigation.navigate(RootStackRoutes.AppTabs, { + screen: AppTabsRoutes.HomeStack, + params: { screen: HomeStackRoutes.Home }, + }); + }; + + const showReviewCancellationAlert = () => + setTimeout( + // Timeout is needed to prevent the alert from being shown before the redirect from @suite-native/device - useHandleDeviceConnection hook happens. + () => + showAlert({ + title: , + description: ( + + ), + primaryButtonTitle: ( + + ), + primaryButtonVariant: 'redBold', + secondaryButtonVariant: 'redElevation0', + secondaryButtonTitle: , + onPressPrimaryButton: handleReconnect, + onPressSecondaryButton: handleCancel, + }), + 1000, + ); + + return showReviewCancellationAlert; +}; diff --git a/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx b/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx index 765b1ca8001..499557b48f4 100644 --- a/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx +++ b/suite-native/module-send/src/screens/SendAddressReviewScreen.tsx @@ -44,6 +44,9 @@ export const SendAddressReviewScreen = ({ useEffect(() => { const unsubscribe = navigation.addListener('beforeRemove', e => { + // We want to modify only behavior of back button actions. + if (e.data.action.type !== 'GO_BACK') return; + if (isReviewInProgress) { e.preventDefault(); showReviewCancellationAlert(); diff --git a/suite-native/module-send/src/sendOutputsFormSchema.ts b/suite-native/module-send/src/sendOutputsFormSchema.ts index b32e7c373f0..559f53204f0 100644 --- a/suite-native/module-send/src/sendOutputsFormSchema.ts +++ b/suite-native/module-send/src/sendOutputsFormSchema.ts @@ -1,6 +1,6 @@ import { G } from '@mobily/ts-belt'; -import { BigNumber } from '@trezor/utils/src/bigNumber'; +import { BigNumber } from '@trezor/utils'; import { NetworkSymbol } from '@suite-common/wallet-config'; import { formatNetworkAmount, isAddressValid, isDecimalsValid } from '@suite-common/wallet-utils'; import { FeeInfo } from '@suite-common/wallet-types'; diff --git a/suite-native/module-send/tsconfig.json b/suite-native/module-send/tsconfig.json index 826cb0caac2..813e560542c 100644 --- a/suite-native/module-send/tsconfig.json +++ b/suite-native/module-send/tsconfig.json @@ -42,12 +42,13 @@ { "path": "../navigation" }, { "path": "../qr-code" }, { "path": "../settings" }, - { "path": "../toasts" }, { "path": "../../packages/blockchain-link-types" }, { "path": "../../packages/react-utils" }, { "path": "../../packages/styles" }, - { "path": "../../packages/theme" } + { "path": "../../packages/theme" }, + { "path": "../../packages/transport" }, + { "path": "../../packages/utils" } ] } diff --git a/suite-native/navigation/src/types.tsx b/suite-native/navigation/src/types.tsx index 2640a977238..75e1381f48a 100644 --- a/suite-native/navigation/src/types.tsx +++ b/suite-native/navigation/src/types.tsx @@ -71,4 +71,4 @@ export type TabsOptions = { export type NavigateParameters = Parameters< NavigationHelpers['navigate'] ->; +>[0]; diff --git a/yarn.lock b/yarn.lock index b15ff352e94..cec1ceb0070 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10358,11 +10358,12 @@ __metadata: "@suite-native/navigation": "workspace:*" "@suite-native/qr-code": "workspace:*" "@suite-native/settings": "workspace:*" - "@suite-native/toasts": "workspace:*" "@trezor/blockchain-link-types": "workspace:*" "@trezor/react-utils": "workspace:*" "@trezor/styles": "workspace:*" "@trezor/theme": "workspace:*" + "@trezor/transport": "workspace:*" + "@trezor/utils": "workspace:*" expo-linear-gradient: "npm:13.0.2" react: "npm:18.2.0" react-hook-form: "npm:^7.53.0"