diff --git a/apps/wallet-mobile/.env b/apps/wallet-mobile/.env index 17db531d54..a1031aea55 100644 --- a/apps/wallet-mobile/.env +++ b/apps/wallet-mobile/.env @@ -3,7 +3,7 @@ COMMIT=093dec95a BUILD_VARIANT=STAGING SENTRY_DSN=https://fb3745d47d994059917e358dae581466@o1138840.ingest.sentry.io/4505319746764800 -DISABLE_LOGBOX=true +DISABLE_LOGBOX=false WALLET_1_MNEMONIC=abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon address WALLET_1_NETWORK_ID=300 @@ -20,3 +20,5 @@ FRONTEND_FEE_ADDRESS_MAINNET=addr1q9ry6jfdgm0lcrtfpgwrgxg7qfahv80jlghhrthy6w8hmy FRONTEND_FEE_ADDRESS_PREPROD=addr_test1qrgpjmyy8zk9nuza24a0f4e7mgp9gd6h3uayp0rqnjnkl54v4dlyj0kwfs0x4e38a7047lymzp37tx0y42glslcdtzhqzp57km UNSTOPPABLE_API_KEY=czsajliz-wxgu6tujd1zqq7hey_pclfqhdjsqolsxjfsurgh + +LOGGER_FILTER= diff --git a/apps/wallet-mobile/.storybook/storybook.requires.js b/apps/wallet-mobile/.storybook/storybook.requires.js index 3c33e85fd6..cfe07ed9ad 100644 --- a/apps/wallet-mobile/.storybook/storybook.requires.js +++ b/apps/wallet-mobile/.storybook/storybook.requires.js @@ -197,7 +197,7 @@ const getStories = () => { "./src/features/SetupWallet/common/CardAboutPhrase/CardAboutPhrase.stories.tsx": require("../src/features/SetupWallet/common/CardAboutPhrase/CardAboutPhrase.stories.tsx"), "./src/features/SetupWallet/common/LearnMoreButton/LearnMoreButton.stories.tsx": require("../src/features/SetupWallet/common/LearnMoreButton/LearnMoreButton.stories.tsx"), "./src/features/SetupWallet/common/LogoBanner/LogoBanner.stories.tsx": require("../src/features/SetupWallet/common/LogoBanner/LogoBanner.stories.tsx"), - "./src/features/SetupWallet/common/PreparingWallet/PreparingWallet.stories.tsx": require("../src/features/SetupWallet/common/PreparingWallet/PreparingWallet.stories.tsx"), + "./src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.stories.tsx": require("../src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.stories.tsx"), "./src/features/SetupWallet/common/StepperProgress/StepperProgress.stories.tsx": require("../src/features/SetupWallet/common/StepperProgress/StepperProgress.stories.tsx"), "./src/features/SetupWallet/common/TextInput/TextInput.stories.tsx": require("../src/features/SetupWallet/common/TextInput/TextInput.stories.tsx"), "./src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.stories.tsx": require("../src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.stories.tsx"), diff --git a/apps/wallet-mobile/src/YoroiApp.tsx b/apps/wallet-mobile/src/YoroiApp.tsx index 1bc359cd7d..6346417967 100644 --- a/apps/wallet-mobile/src/YoroiApp.tsx +++ b/apps/wallet-mobile/src/YoroiApp.tsx @@ -18,7 +18,7 @@ import {SelectedWalletProvider} from './features/WalletManager/context/SelectedW import {SelectedWalletMetaProvider} from './features/WalletManager/context/SelectedWalletMetaContext' import {WalletManagerProvider} from './features/WalletManager/context/WalletManagerContext' import {InitApp} from './InitApp' -import {disableLogbox} from './kernel/env' +import {disableLogbox, loggerFilter} from './kernel/env' import {LanguageProvider} from './kernel/i18n' import {useSetupLogger} from './kernel/logger/hooks/useSetupLogger' import {makeMetricsManager, MetricsProvider} from './kernel/metrics/metricsManager' @@ -29,7 +29,11 @@ import {useThemeStorageMaker} from './yoroi-wallets/hooks' enableScreens(true) enableFreeze(true) -if (disableLogbox) LogBox.ignoreAllLogs() +if (disableLogbox) { + LogBox.ignoreAllLogs() +} else { + LogBox.ignoreLogs(['Require cycle:']) +} const queryClient = new QueryClient() const metricsManager = makeMetricsManager() @@ -74,7 +78,7 @@ const Yoroi = () => { } export const YoroiApp = () => { - const isReady = useSetupLogger() + const isReady = useSetupLogger(loggerFilter) if (!isReady) return null diff --git a/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx b/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx index d725d7c6ee..ac52b02a1a 100644 --- a/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx +++ b/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx @@ -9,29 +9,5 @@ export const useNavigateTo = () => { return useRef({ exchangeSelectBuyProvider: () => navigation.navigate('exchange-select-buy-provider'), exchangeSelectSellProvider: () => navigation.navigate('exchange-select-sell-provider'), - exchangeOpenOrder: () => - navigation.reset({ - index: 0, - routes: [ - { - name: 'manage-wallets', - state: { - routes: [ - {name: 'wallet-selection'}, - { - name: 'main-wallet-routes', - state: { - routes: [ - { - name: 'history-list', - }, - ], - }, - }, - ], - }, - }, - ], - }), }).current } diff --git a/apps/wallet-mobile/src/features/Exchange/useCases/CreateExchangeOrderScreen/CreateExchangeOrderScreen.tsx b/apps/wallet-mobile/src/features/Exchange/useCases/CreateExchangeOrderScreen/CreateExchangeOrderScreen.tsx index 762deb2c02..dd0dae5a17 100644 --- a/apps/wallet-mobile/src/features/Exchange/useCases/CreateExchangeOrderScreen/CreateExchangeOrderScreen.tsx +++ b/apps/wallet-mobile/src/features/Exchange/useCases/CreateExchangeOrderScreen/CreateExchangeOrderScreen.tsx @@ -12,6 +12,7 @@ import {Space} from '../../../../components/Space/Space' import {Warning} from '../../../../components/Warning' import {banxaTestWallet} from '../../../../kernel/env' import {useMetrics} from '../../../../kernel/metrics/metricsManager' +import {useWalletNavigation} from '../../../../kernel/navigation' import {useTokenInfo} from '../../../../yoroi-wallets/hooks' import {Quantities} from '../../../../yoroi-wallets/utils' import {useSelectedWallet} from '../../../WalletManager/context/SelectedWalletContext' @@ -31,6 +32,7 @@ export const CreateExchangeOrderScreen = () => { const styles = useStyles() const {track} = useMetrics() const wallet = useSelectedWallet() + const walletNavigation = useWalletNavigation() const [contentHeight, setContentHeight] = React.useState(0) const navigateTo = useNavigateTo() @@ -88,7 +90,7 @@ export const CreateExchangeOrderScreen = () => { if (referralLink.toString() !== '') { Linking.openURL(referralLink.toString()) track.exchangeSubmitted({ramp_type: orderType === 'sell' ? 'Sell' : 'Buy', ada_amount: orderAmount}) - navigateTo.exchangeOpenOrder() + walletNavigation.navigateToTxHistory() } }, }, diff --git a/apps/wallet-mobile/src/features/SetupWallet/SetupWalletNavigator.tsx b/apps/wallet-mobile/src/features/SetupWallet/SetupWalletNavigator.tsx index 6afdcacef2..eab1b3538a 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/SetupWalletNavigator.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/SetupWalletNavigator.tsx @@ -4,6 +4,7 @@ import * as React from 'react' import {defineMessages, useIntl} from 'react-intl' import {defaultStackNavigationOptions, WalletInitRoutes} from '../../kernel/navigation' +import {PreparingWalletScreen} from './common/PreparingWalletScreen/PreparingWalletScreen' import {CheckNanoXScreen} from './legacy/CheckNanoX/CheckNanoXScreen' import {ConnectNanoXScreen} from './legacy/ConnectNanoX/ConnectNanoXScreen' import {ImportReadOnlyWalletScreen} from './legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen' @@ -134,6 +135,12 @@ export const SetupWalletNavigator = () => { component={VerifyRecoveryPhraseScreen} options={{title: strings.createWalletTitle}} /> + + ) } diff --git a/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.tsx b/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.tsx deleted file mode 100644 index 8d5b09a75f..0000000000 --- a/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import {useTheme} from '@yoroi/theme' -import * as React from 'react' -import {StyleSheet, Text, View} from 'react-native' - -import {useStrings} from '../useStrings' - -export const PreparingWallet = () => { - const strings = useStrings() - const {styles} = useStyles() - - return ( - - {strings.preparingWallet} - - ) -} - -const useStyles = () => { - const {atoms, color} = useTheme() - const styles = StyleSheet.create({ - root: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - color: color.primary_c500, - textAlign: 'center', - ...atoms.heading_2_medium, - }, - }) - - return {styles} as const -} diff --git a/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.stories.tsx b/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.stories.tsx similarity index 74% rename from apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.stories.tsx rename to apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.stories.tsx index 7f59e3acdd..93fc7f8ee3 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWallet/PreparingWallet.stories.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.stories.tsx @@ -2,11 +2,11 @@ import {storiesOf} from '@storybook/react-native' import React from 'react' import {StyleSheet, View} from 'react-native' -import {PreparingWallet} from './PreparingWallet' +import {PreparingWalletScreen} from './PreparingWalletScreen' storiesOf('AddWallet PreparingWallet', module) .addDecorator((story) => {story()}) - .add('initial', () => ) + .add('initial', () => ) const styles = StyleSheet.create({ container: { diff --git a/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.tsx new file mode 100644 index 0000000000..60d7808868 --- /dev/null +++ b/apps/wallet-mobile/src/features/SetupWallet/common/PreparingWalletScreen/PreparingWalletScreen.tsx @@ -0,0 +1,52 @@ +import {useSetupWallet} from '@yoroi/setup-wallet' +import {useTheme} from '@yoroi/theme' +import * as React from 'react' +import {StyleSheet, Text} from 'react-native' +import {SafeAreaView} from 'react-native-safe-area-context' + +import {logger} from '../../../../kernel/logger/logger' +import {isEmptyString} from '../../../../kernel/utils' +import {useLaunchWalletAfterSyncing} from '../../../WalletManager/common/useLaunchWalletAfterSyncing' +import {useSyncTemporarilyPaused} from '../../../WalletManager/common/useSyncTemporarilyPaused' +import {useStrings} from '../useStrings' + +/** + * It requests the global syncing to stop on mounting to favor the sync of a specific wallet + * and resume the global syncing after the wallet is sync and the screen is unmounted. + */ +export const PreparingWalletScreen = () => { + const strings = useStrings() + const {styles} = useStyles() + const {walletId} = useSetupWallet() + const isGlobalSyncPaused = useSyncTemporarilyPaused() + useLaunchWalletAfterSyncing({isGlobalSyncPaused, walletId}) + + if (isEmptyString(walletId)) { + const error = new Error('PreparingWalletScreen: walletId is empty, reached an invalid state.') + logger.error(error) + throw error + } + + return ( + + {strings.preparingWallet} + + ) +} + +const useStyles = () => { + const {atoms, color} = useTheme() + const styles = StyleSheet.create({ + root: { + ...atoms.flex_1, + ...atoms.align_center, + ...atoms.justify_center, + }, + title: { + color: color.primary_c500, + ...atoms.text_center, + ...atoms.heading_2_medium, + }, + }) + return {styles} as const +} diff --git a/apps/wallet-mobile/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.tsx index ded8afe055..a1826069a0 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.tsx @@ -9,13 +9,13 @@ import {SafeAreaView} from 'react-native-safe-area-context' import image from '../../../../assets/img/ledger_1.png' import {BulletPointItem, Button, ProgressStep, Spacer, Text} from '../../../../components' import {confirmationMessages, ledgerMessages} from '../../../../kernel/i18n/global-messages' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' export const CheckNanoXScreen = () => { const strings = useStrings() const styles = useStyles() - const navigation = useNavigation() + const navigation = useNavigation() const onContinue = () => navigation.navigate('setup-wallet-connect-nano-x') const {useUSB} = useSetupWallet() diff --git a/apps/wallet-mobile/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.tsx index e0e9e6c134..b918b36101 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.tsx @@ -10,7 +10,7 @@ import {ProgressStep} from '../../../../components' import {showErrorDialog} from '../../../../kernel/dialogs' import {errorMessages} from '../../../../kernel/i18n/global-messages' import LocalizableError from '../../../../kernel/i18n/LocalizableError' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {LedgerConnect} from '../../../../legacy/HW' import {getHWDeviceInfo} from '../../../../yoroi-wallets/cardano/hw' import {DeviceId, DeviceObj, HWDeviceInfo} from '../../../../yoroi-wallets/hw' @@ -30,7 +30,7 @@ export const ConnectNanoXScreen = ({defaultDevices}: Props) => { const intl = useIntl() const strings = useStrings() const styles = useStyles() - const navigation = useNavigation() + const navigation = useNavigation() const {hwDeviceInfoChanged, walletImplementationId, useUSB} = useSetupWallet() diff --git a/apps/wallet-mobile/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.tsx index 1c09f29db7..fefbf46dd6 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.tsx @@ -8,13 +8,13 @@ import {BulletPointItem, CameraCodeScanner, Spacer, Text} from '../../../../comp import {showErrorDialog} from '../../../../kernel/dialogs' import {errorMessages} from '../../../../kernel/i18n/global-messages' import {logger} from '../../../../kernel/logger/logger' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {isCIP1852AccountPath, isValidPublicKey} from '../../../../yoroi-wallets/cardano/bip44Validators' export const ImportReadOnlyWalletScreen = () => { const intl = useIntl() const strings = useStrings() - const navigation = useNavigation() + const navigation = useNavigation() const {publicKeyHexChanged, pathChanged} = useSetupWallet() const onRead = async (event: {data: string}): Promise => { diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseMnemonicType/ChooseMnemonicTypeScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseMnemonicType/ChooseMnemonicTypeScreen.tsx index b976f5f30f..0d8ed7d1f9 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseMnemonicType/ChooseMnemonicTypeScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseMnemonicType/ChooseMnemonicTypeScreen.tsx @@ -7,7 +7,7 @@ import {SafeAreaView} from 'react-native-safe-area-context' import {Space} from '../../../../components/Space/Space' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {ButtonCard} from '../../common/ButtonCard/ButtonCard' import {LogoBanner} from '../../common/LogoBanner/LogoBanner' import {useStrings} from '../../common/useStrings' @@ -20,7 +20,7 @@ export const ChooseMnemonicTypeScreen = () => { const {mnemonicTypeChanged} = useSetupWallet() const {track} = useMetrics() - const navigation = useNavigation() + const navigation = useNavigation() const handle15Words = () => { mnemonicTypeChanged(15) diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseNetwork/ChooseNetworkScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseNetwork/ChooseNetworkScreen.tsx index bcd10eff6f..d31356fae9 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseNetwork/ChooseNetworkScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseNetwork/ChooseNetworkScreen.tsx @@ -6,7 +6,7 @@ import {ScrollView, StyleSheet, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {Space} from '../../../../components/Space/Space' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import * as HASKELL_SHELLEY from '../../../../yoroi-wallets/cardano/constants/mainnet/constants' import * as SANCHONET from '../../../../yoroi-wallets/cardano/constants/sanchonet/constants' import * as HASKELL_SHELLEY_TESTNET from '../../../../yoroi-wallets/cardano/constants/testnet/constants' @@ -91,7 +91,7 @@ const useNavigate = () => { } export const useNavigateTo = () => { - const navigation = useNavigation() + const navigation = useNavigation() return React.useRef({ create: () => navigation.navigate('setup-wallet-about-recovery-phase'), diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseSetupType/ChooseSetupTypeScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseSetupType/ChooseSetupTypeScreen.tsx index 31d9f2f909..cdfd15b7f9 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseSetupType/ChooseSetupTypeScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/ChooseSetupType/ChooseSetupTypeScreen.tsx @@ -8,7 +8,7 @@ import {SafeAreaView} from 'react-native-safe-area-context' import {Space} from '../../../../components/Space/Space' import {isProduction} from '../../../../kernel/env' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {LedgerTransportSwitchModal} from '../../../../legacy/HW' import * as HASKELL_SHELLEY from '../../../../yoroi-wallets/cardano/constants/mainnet/constants' import {ButtonCard} from '../../common/ButtonCard/ButtonCard' @@ -36,7 +36,7 @@ export const ChooseSetupTypeScreen = () => { }, [track]), ) - const navigation = useNavigation() + const navigation = useNavigation() const handleCreate = () => { walletImplementationIdChanged(HASKELL_SHELLEY.WALLET_IMPLEMENTATION_ID) diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/AboutRecoveryPhraseScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/AboutRecoveryPhraseScreen.tsx index 0abc4bf99d..7ea2c70abb 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/AboutRecoveryPhraseScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/AboutRecoveryPhraseScreen.tsx @@ -8,7 +8,7 @@ import {ViewProps} from 'react-native-svg/lib/typescript/fabric/utils' import {Button, Spacer} from '../../../../components' import {Space} from '../../../../components/Space/Space' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase' import {YoroiZendeskLink} from '../../common/constants' import {LearnMoreButton} from '../../common/LearnMoreButton/LearnMoreButton' @@ -19,7 +19,7 @@ export const AboutRecoveryPhraseScreen = () => { const bold = useBold() const {styles} = useStyles() const strings = useStrings() - const navigation = useNavigation() + const navigation = useNavigation() const {track} = useMetrics() useFocusEffect( diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/RecoveryPhraseScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/RecoveryPhraseScreen.tsx index 41f82ae5d3..5af1e8bb54 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/RecoveryPhraseScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/RecoveryPhraseScreen.tsx @@ -10,7 +10,7 @@ import {SafeAreaView} from 'react-native-safe-area-context' import {Button, Spacer, useModal} from '../../../../components' import {Space} from '../../../../components/Space/Space' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {generateAdaMnemonic} from '../../../../yoroi-wallets/cardano/mnemonic' import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase' import {YoroiZendeskLink} from '../../common/constants' @@ -25,7 +25,7 @@ export const RecoveryPhraseScreen = () => { const {styles, colors} = useStyles() const {openModal, closeModal} = useModal() const [isBlur, setIsBlur] = React.useState(true) - const navigation = useNavigation() + const navigation = useNavigation() const strings = useStrings() const {mnemonicChanged, showCreateWalletInfoModal, showCreateWalletInfoModalChanged} = useSetupWallet() const {track} = useMetrics() diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/VerifyRecoveryPhraseScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/VerifyRecoveryPhraseScreen.tsx index 4f039e0f83..5c4cfadbc4 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/VerifyRecoveryPhraseScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/VerifyRecoveryPhraseScreen.tsx @@ -11,7 +11,7 @@ import {SafeAreaView} from 'react-native-safe-area-context' import {Button} from '../../../../components' import {Space} from '../../../../components/Space/Space' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {makeKeys} from '../../../../yoroi-wallets/cardano/shelley/makeKeys' import {StepperProgress} from '../../common/StepperProgress/StepperProgress' import {useStrings} from '../../common/useStrings' @@ -21,7 +21,7 @@ import {Check2 as Check2Illustration} from '../../illustrations/Check2' export const VerifyRecoveryPhraseScreen = () => { const {styles} = useStyles() const bold = useBold() - const navigation = useNavigation() + const navigation = useNavigation() const strings = useStrings() const {mnemonic, publicKeyHexChanged} = useSetupWallet() const {track} = useMetrics() diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/WalletDetailsScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/WalletDetailsScreen.tsx index 8b8ec711bc..1d953e95a7 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/WalletDetailsScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/CreateWallet/WalletDetailsScreen.tsx @@ -1,4 +1,4 @@ -import {useFocusEffect} from '@react-navigation/native' +import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useAsyncStorage} from '@yoroi/common' import {useSetupWallet} from '@yoroi/setup-wallet' import {useTheme} from '@yoroi/theme' @@ -23,8 +23,9 @@ import {Button, Icon, KeyboardAvoidingView, TextInput, useModal} from '../../../ import {Space} from '../../../../components/Space/Space' import {showErrorDialog} from '../../../../kernel/dialogs' import {errorMessages} from '../../../../kernel/i18n/global-messages' +import {logger} from '../../../../kernel/logger/logger' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {useWalletNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {isEmptyString} from '../../../../kernel/utils' import {useCreateWallet, usePlate, useWalletNames} from '../../../../yoroi-wallets/hooks' import {WalletImplementationId} from '../../../../yoroi-wallets/types' @@ -37,11 +38,12 @@ import { import {debugWalletInfo, features} from '../../..' import {AddressMode} from '../../../WalletManager/common/types' import {parseWalletMeta} from '../../../WalletManager/common/validators' +import {useSetSelectedWallet} from '../../../WalletManager/context/SelectedWalletContext' +import {useSetSelectedWalletMeta} from '../../../WalletManager/context/SelectedWalletMetaContext' import {useWalletManager} from '../../../WalletManager/context/WalletManagerContext' import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase' import {YoroiZendeskLink} from '../../common/constants' import {LearnMoreButton} from '../../common/LearnMoreButton/LearnMoreButton' -import {PreparingWallet} from '../../common/PreparingWallet/PreparingWallet' import {StepperProgress} from '../../common/StepperProgress/StepperProgress' import {useStrings} from '../../common/useStrings' import {Info as InfoIcon} from '../../illustrations/Info' @@ -63,15 +65,15 @@ const useSizeModal = () => { // when restoring, later will be part of the onboarding const addressMode: AddressMode = 'single' export const WalletDetailsScreen = () => { - const bold = useBold() + const navigation = useNavigation() + const strings = useStrings() const {styles} = useStyles() + const {track} = useMetrics() + const bold = useBold() const {HEIGHT_MODAL_NAME_PASSWORD, HEIGHT_MODAL_CHECKSUM} = useSizeModal() const {openModal, closeModal} = useModal() - const {resetToTxHistory} = useWalletNavigation() - const strings = useStrings() const walletManager = useWalletManager() const {walletNames} = useWalletNames(walletManager) - const {track} = useMetrics() const intl = useIntl() const storage = useAsyncStorage() const { @@ -81,7 +83,10 @@ export const WalletDetailsScreen = () => { walletImplementationId, showRestoreWalletInfoModal, showRestoreWalletInfoModalChanged, + walletIdChanged, } = useSetupWallet() + const selectWalletMeta = useSetSelectedWalletMeta() + const selectWallet = useSetSelectedWallet() const plate = usePlate({networkId, publicKeyHex}) const [name, setName] = React.useState(features.prefillWalletInfo ? debugWalletInfo.WALLET_NAME : '') const passwordRef = React.useRef(null) @@ -111,15 +116,23 @@ export const WalletDetailsScreen = () => { isSuccess: isCreateWalletSuccess, } = useCreateWallet({ onSuccess: async (wallet) => { + walletIdChanged(wallet.id) const walletStorage = storage.join('wallet/') const walletMeta = await walletStorage.getItem(wallet.id, parseWalletMeta) - if (!walletMeta) throw new Error('invalid wallet meta') + if (!walletMeta) { + const error = new Error('WalletDetailsScreen: wallet meta is invalid, reached an invalid state.') + logger.error(error) + throw error + } + + selectWallet(wallet) + selectWalletMeta(walletMeta) + walletManager.setSelectedWalletId(wallet.id) track.createWalletDetailsSettled() - // TODO: revisit needs to open the new wallet - should wait for done sync event from manager - resetToTxHistory() + navigation.navigate('setup-wallet-preparing-wallet') }, onError: (error) => { InteractionManager.runAfterInteractions(() => { @@ -251,8 +264,6 @@ export const WalletDetailsScreen = () => { ) } - if (isLoading) return - return ( diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletDetailsScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletDetailsScreen.tsx index 2659c2d5ff..95ba5fc9b7 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletDetailsScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletDetailsScreen.tsx @@ -1,4 +1,4 @@ -import {useFocusEffect} from '@react-navigation/native' +import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useAsyncStorage} from '@yoroi/common' import {useSetupWallet} from '@yoroi/setup-wallet' import {useTheme} from '@yoroi/theme' @@ -22,8 +22,9 @@ import {Button, Icon, KeyboardAvoidingView, TextInput, useModal} from '../../../ import {Space} from '../../../../components/Space/Space' import {showErrorDialog} from '../../../../kernel/dialogs' import {errorMessages} from '../../../../kernel/i18n/global-messages' +import {logger} from '../../../../kernel/logger/logger' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {useWalletNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation} from '../../../../kernel/navigation' import {isEmptyString} from '../../../../kernel/utils' import {useCreateWallet, usePlate, useWalletNames} from '../../../../yoroi-wallets/hooks' import {WalletImplementationId} from '../../../../yoroi-wallets/types' @@ -36,11 +37,12 @@ import { import {debugWalletInfo, features} from '../../..' import {AddressMode} from '../../../WalletManager/common/types' import {parseWalletMeta} from '../../../WalletManager/common/validators' +import {useSetSelectedWallet} from '../../../WalletManager/context/SelectedWalletContext' +import {useSetSelectedWalletMeta} from '../../../WalletManager/context/SelectedWalletMetaContext' import {useWalletManager} from '../../../WalletManager/context/WalletManagerContext' import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase' import {YoroiZendeskLink} from '../../common/constants' import {LearnMoreButton} from '../../common/LearnMoreButton/LearnMoreButton' -import {PreparingWallet} from '../../common/PreparingWallet/PreparingWallet' import {StepperProgress} from '../../common/StepperProgress/StepperProgress' import {useStrings} from '../../common/useStrings' import {Info as InfoIcon} from '../../illustrations/Info' @@ -62,19 +64,21 @@ const useSizeModal = () => { // when restoring, later will be part of the onboarding const addressMode: AddressMode = 'single' export const RestoreWalletDetailsScreen = () => { - const bold = useBold() + const navigation = useNavigation() + const strings = useStrings() const {styles} = useStyles() + const {track} = useMetrics() + const bold = useBold() const {HEIGHT_MODAL_NAME_PASSWORD, HEIGHT_MODAL_CHECKSUM} = useSizeModal() const {openModal, closeModal} = useModal() - const strings = useStrings() - const {resetToTxHistory} = useWalletNavigation() const walletManager = useWalletManager() - const {track} = useMetrics() const {walletNames} = useWalletNames(walletManager) const [name, setName] = React.useState(features.prefillWalletInfo ? debugWalletInfo.WALLET_NAME : '') const storage = useAsyncStorage() - const {mnemonic, networkId, publicKeyHex, walletImplementationId} = useSetupWallet() + const {mnemonic, networkId, publicKeyHex, walletImplementationId, walletIdChanged} = useSetupWallet() const plate = usePlate({networkId, publicKeyHex}) + const selectWalletMeta = useSetSelectedWalletMeta() + const selectWallet = useSetSelectedWallet() const passwordRef = React.useRef(null) const [password, setPassword] = React.useState(features.prefillWalletInfo ? debugWalletInfo.PASSWORD : '') @@ -99,14 +103,19 @@ export const RestoreWalletDetailsScreen = () => { isSuccess: isCreateWalletSuccess, } = useCreateWallet({ onSuccess: async (wallet) => { + walletIdChanged(wallet.id) const walletStorage = storage.join('wallet/') const walletMeta = await walletStorage.getItem(wallet.id, parseWalletMeta) - if (!walletMeta) throw new Error('invalid wallet meta') + if (!walletMeta) { + const error = new Error('RestoreWalletDetailsScreen: wallet meta is invalid, reached an invalid state.') + logger.error(error) + throw error + } track.restoreWalletDetailsSettled() - // TODO: revist should open the wallet and navigate to it - resetToTxHistory() + + navigation.navigate('setup-wallet-preparing-wallet') }, onError: (error) => { InteractionManager.runAfterInteractions(() => { @@ -123,8 +132,6 @@ export const RestoreWalletDetailsScreen = () => { }, [track]), ) - if (isLoading) return - const nameErrors = validateWalletName(name, null, walletNames && !isCreateWalletSuccess ? walletNames : []) const walletNameErrorText = getWalletNameError( {tooLong: strings.tooLong, nameAlreadyTaken: strings.nameAlreadyTaken, mustBeFilled: strings.mustBeFilled}, diff --git a/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletScreen.tsx b/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletScreen.tsx index f427d52499..74492f1b48 100644 --- a/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletScreen.tsx +++ b/apps/wallet-mobile/src/features/SetupWallet/useCases/RestoreWallet/RestoreWalletScreen.tsx @@ -11,7 +11,7 @@ import {SafeAreaView} from 'react-native-safe-area-context' import {Button, Icon, KeyboardAvoidingView, useModal} from '../../../../components' import {Space} from '../../../../components/Space/Space' import {useMetrics} from '../../../../kernel/metrics/metricsManager' -import {useWalletNavigation, WalletInitRouteNavigation} from '../../../../kernel/navigation' +import {SetupWalletRouteNavigation, useWalletNavigation} from '../../../../kernel/navigation' import {isEmptyString} from '../../../../kernel/utils' import {makeKeys} from '../../../../yoroi-wallets/cardano/shelley/makeKeys' import {usePlate, useWalletMetas} from '../../../../yoroi-wallets/hooks' @@ -33,13 +33,13 @@ export const RestoreWalletScreen = () => { const strings = useStrings() const bold = useBold() const [mnemonic, setMnemonic] = React.useState('') - const navigation = useNavigation() + const navigation = useNavigation() const {publicKeyHexChanged, mnemonicChanged, mnemonicType} = useSetupWallet() const {track} = useMetrics() const walletManager = useWalletManager() const {walletMetas} = useWalletMetas(walletManager) const {openModal} = useModal() - const {navigateToTxHistory} = useWalletNavigation() + const {resetToTxHistory} = useWalletNavigation() const selectWalletMeta = useSetSelectedWalletMeta() const selectWallet = useSetSelectedWallet() const [focusedIndex, setFocusedIndex] = React.useState(0) @@ -120,9 +120,9 @@ export const RestoreWalletScreen = () => { const wallet = walletManager.getOpenedWalletById(walletMeta.id) selectWallet(wallet) walletManager.setSelectedWalletId(walletMeta.id) - navigateToTxHistory() + resetToTxHistory() }, - [selectWalletMeta, walletManager, selectWallet, navigateToTxHistory], + [selectWalletMeta, walletManager, selectWallet, resetToTxHistory], ) const handleOnNext = React.useCallback(async () => { diff --git a/apps/wallet-mobile/src/features/Swap/common/navigation.ts b/apps/wallet-mobile/src/features/Swap/common/navigation.ts index 556fe8450c..93d89633e8 100644 --- a/apps/wallet-mobile/src/features/Swap/common/navigation.ts +++ b/apps/wallet-mobile/src/features/Swap/common/navigation.ts @@ -4,50 +4,30 @@ import {useRef} from 'react' import {SwapTokenRouteseNavigation} from '../../../kernel/navigation' export const useNavigateTo = () => { - const navigation = useNavigation() + const swapNavigation = useNavigation() + const navigation = useNavigation() return useRef({ - selectPool: () => navigation.navigate('swap-select-pool'), - editSlippage: () => navigation.navigate('swap-edit-slippage'), - selectBuyToken: () => navigation.navigate('swap-select-buy-token'), - selectSellToken: () => navigation.navigate('swap-select-sell-token'), - startSwap: () => navigation.navigate('swap-start-swap'), - confirmTx: () => navigation.navigate('swap-confirm-tx'), - submittedTx: (txId: string) => navigation.navigate('swap-submitted-tx', {txId}), - failedTx: () => navigation.navigate('swap-failed-tx'), + selectPool: () => swapNavigation.navigate('swap-select-pool'), + editSlippage: () => swapNavigation.navigate('swap-edit-slippage'), + selectBuyToken: () => swapNavigation.navigate('swap-select-buy-token'), + selectSellToken: () => swapNavigation.navigate('swap-select-sell-token'), + startSwap: () => swapNavigation.navigate('swap-start-swap', {screen: 'token-swap'}), + confirmTx: () => swapNavigation.navigate('swap-confirm-tx'), + submittedTx: (txId: string) => swapNavigation.navigate('swap-submitted-tx', {txId}), + failedTx: () => swapNavigation.navigate('swap-failed-tx'), swapOpenOrders: () => - navigation.reset({ - index: 0, - routes: [ - { - name: 'manage-wallets', - state: { - routes: [ - {name: 'wallet-selection'}, - { - name: 'main-wallet-routes', - state: { - routes: [ - { - name: 'history', - state: { - routes: [ - { - name: 'swap-start-swap', - state: { - routes: [{name: 'orders'}], - }, - }, - ], - }, - }, - ], - }, - }, - ], + navigation.navigate('manage-wallets', { + screen: 'main-wallet-routes', + params: { + screen: 'history', + params: { + screen: 'swap-start-swap', + params: { + screen: 'orders', }, }, - ], + }, }), }).current } diff --git a/apps/wallet-mobile/src/features/WalletManager/common/useLaunchWalletAfterSyncing.tsx b/apps/wallet-mobile/src/features/WalletManager/common/useLaunchWalletAfterSyncing.tsx new file mode 100644 index 0000000000..7bd094a417 --- /dev/null +++ b/apps/wallet-mobile/src/features/WalletManager/common/useLaunchWalletAfterSyncing.tsx @@ -0,0 +1,73 @@ +import * as React from 'react' + +import {time} from '../../../kernel/constants' +import {logger} from '../../../kernel/logger/logger' +import {useWalletNavigation} from '../../../kernel/navigation' +import {YoroiWallet} from '../../../yoroi-wallets/cardano/types' +import {useSetSelectedWallet} from '../context/SelectedWalletContext' +import {useSetSelectedWalletMeta} from '../context/SelectedWalletMetaContext' +import {useWalletManager} from '../context/WalletManagerContext' + +/** + * Custom hook to launch a new wallet first time or when a previous sync is required, it will follow these steps: + * preconditions: + * 1. wallet should be previously created + * process: + * 2. wait 1s to display any UI feedback (like a spinner) + * 3. request pause of global sync + * 4. open the wallets (to populate the wallets in the manager) + * 5. check if the wallet provided is there (if not, silently redirect to wallet selection) (error is reported if user has enabled crash reporting) + * 6. sync the wallet (with force flag) + * 7. redirect user to the tx history screen (aka home screen) + * + * This **must be used only** to launch a wallet after it has been created/restore or in last case when it **requires** a sync + * for every other case use wallet manager setCurrentWallet (setSelectedWallet and setSelectedWalletMeta will be deprecated) + * check `SelectWalletFromList` useCase in the WalletManager feature for more details + * + * @param {YoroiWallet['id']} id - The ID of the wallet to launch + * @summary This is for launching a wallet after it has been created/restore/required-sync **only**, don't use to select a wallet + */ +export function useLaunchWalletAfterSyncing({ + isGlobalSyncPaused = false, + walletId, +}: { + isGlobalSyncPaused: boolean + walletId: YoroiWallet['id'] | null +}) { + const walletNavigation = useWalletNavigation() + const manager = useWalletManager() + const setSelectedWallet = useSetSelectedWallet() + const setSelectedWalletMeta = useSetSelectedWalletMeta() + + React.useEffect(() => { + let started = false + if (!isGlobalSyncPaused || started || walletId == null) return + + const process = async () => { + started = true + // openning wallets force manager to add it to the sync queue + // it's ok if the wallet is already opened by manager + const {metas} = await manager.openWallets() + + const wallet = manager.getOpenedWalletById(walletId) + const meta = metas.find(({id}) => id === walletId) + if (!wallet || !meta) { + const error = new Error( + 'useLaunchWalletAfterSyncing: New wallet/meta has not been found, reached an invalid state', + ) + logger.error(error) + walletNavigation.resetToWalletSelection() + return + } + + setSelectedWallet(wallet) + setSelectedWalletMeta(meta) + await wallet.sync({isForced: true}) + + walletNavigation.resetToTxHistory() + } + + const timer = setTimeout(() => process(), time.oneSecond) + return () => clearTimeout(timer) + }, [isGlobalSyncPaused, walletId, manager, walletNavigation, setSelectedWallet, setSelectedWalletMeta]) +} diff --git a/apps/wallet-mobile/src/features/WalletManager/common/useSyncTemporarilyPaused.tsx b/apps/wallet-mobile/src/features/WalletManager/common/useSyncTemporarilyPaused.tsx new file mode 100644 index 0000000000..64bc45d9cf --- /dev/null +++ b/apps/wallet-mobile/src/features/WalletManager/common/useSyncTemporarilyPaused.tsx @@ -0,0 +1,39 @@ +import * as React from 'react' + +import {useWalletManager} from '../context/WalletManagerContext' + +/** + * This is used to stop syncing and resume syncing automaticaly + * (stop on mount and resume on unmount) + * when there is an action that requires syncing to be stopped + * + * @summary This is for stopping syncing and resuming syncing automaticaly + * when the screen is unmounted + * @returns {boolean} isTemporarilyPaused - A boolean to indicate if syncing is stopped + */ +export function useSyncTemporarilyPaused() { + const manager = useWalletManager() + const [isSyncTemporarilyPaused, setIsSyncTemporarilyPaused] = React.useState( + !manager.isSyncActive && !manager.isSyncing, + ) + + React.useEffect(() => { + manager.pauseSyncing() + + const subSyncActivity = manager.syncActive$.subscribe((isActive) => { + setIsSyncTemporarilyPaused(() => !isActive && !manager.isSyncing) + }) + const subIsSyncing = manager.syncing$.subscribe((isSyncing) => { + setIsSyncTemporarilyPaused(() => !isSyncing) + }) + + return () => { + subSyncActivity.unsubscribe() + subIsSyncing.unsubscribe() + + manager.resumeSyncing() + } + }, [manager]) + + return isSyncTemporarilyPaused +} diff --git a/apps/wallet-mobile/src/features/WalletManager/common/walletManager.ts b/apps/wallet-mobile/src/features/WalletManager/common/walletManager.ts index d97f62a5a1..56da7bfdd3 100644 --- a/apps/wallet-mobile/src/features/WalletManager/common/walletManager.ts +++ b/apps/wallet-mobile/src/features/WalletManager/common/walletManager.ts @@ -1,4 +1,4 @@ -import {parseSafe} from '@yoroi/common' +import {difference, parseSafe} from '@yoroi/common' import {App, Chain} from '@yoroi/types' import { BehaviorSubject, @@ -15,6 +15,7 @@ import { } from 'rxjs' import uuid from 'uuid' +import {logger} from '../../../kernel/logger/logger' import {makeWalletEncryptedStorage} from '../../../kernel/storage/EncryptedStorage' import {Keychain} from '../../../kernel/storage/Keychain' import {rootStorage} from '../../../kernel/storage/rootStorage' @@ -67,6 +68,25 @@ export class WalletManager { return this.#selectedWalletId } + private initWalletInfos(wallets: ReadonlyArray) { + for (const wallet of wallets) { + this.#walletInfos.set(wallet.id, { + sync: {status: 'waiting', updatedAt: Date.now()}, + }) + this.walletInfos$.next(new Map(this.#walletInfos)) + } + + // drop wallets that are not returned by the list (deleted wallets) + // can't delete on removeWallet cuz a wallet can be marked to be deleted while it's syncing + difference( + wallets.map(({id}) => id), + Array.from(this.#walletInfos.keys()), + ).forEach((id) => { + this.#walletInfos.delete(id) + this.walletInfos$.next(new Map(this.#walletInfos)) + }) + } + startSyncingAllWallets() { const syncWallets = () => { if (this.#isSyncing$.value) return @@ -75,27 +95,26 @@ export class WalletManager { from(this.openWallets()) .pipe( - concatMap((wallets) => { - this.#walletInfos.clear() - wallets.forEach((wallet) => { - this.#walletInfos.set(wallet.id, {sync: {status: 'waiting', updatedAt: Date.now()}}) - this.walletInfos$.next(new Map(this.#walletInfos)) - }) + concatMap(({wallets}) => { + this.initWalletInfos(wallets) return from(wallets) }), concatMap((wallet) => { this.#walletInfos.set(wallet.id, {sync: {status: 'syncing', updatedAt: Date.now()}}) this.walletInfos$.next(new Map(this.#walletInfos)) + logger.debug('WalletManager: startSyncingAllWallets syncing walet', {walletId: wallet.id}) return from(wallet.sync({isForced: false})).pipe( catchError((error) => { this.#walletInfos.set(wallet.id, {sync: {status: 'error', error, updatedAt: Date.now()}}) this.walletInfos$.next(new Map(this.#walletInfos)) + logger.error('WalletManager: startSyncingAllWallets error syncing walet', {error, walletId: wallet.id}) return of() }), finalize(() => { if (this.#walletInfos.get(wallet.id)?.sync.status !== 'error') { this.#walletInfos.set(wallet.id, {sync: {status: 'done', updatedAt: Date.now()}}) this.walletInfos$.next(new Map(this.#walletInfos)) + logger.debug('WalletManager: startSyncingAllWallets done syncing walet', {walletId: wallet.id}) } }), ) @@ -141,10 +160,12 @@ export class WalletManager { } pauseSyncing() { + logger.debug('WalletManager: pauseSyncing requested') this.#syncControl$.next(false) } resumeSyncing() { + logger.debug('WalletManager: resumeSyncing requested') this.#syncControl$.next(true) } @@ -164,12 +185,19 @@ export class WalletManager { return this.#openedWallets.get(id) } + /** + * It populates the wallet manager with the wallets stored in the storage + * and ensures that after a wallet is loaded that instance is returned on subsequent calls + * A wallet should be instantianted only here, otherwise the stream mechanism will not work + * + * @returns {Promise<{wallets: YoroiWallet[]; metas: WalletMeta[]}>} + */ async openWallets() { const walletMetas = await this.listWallets() const closedWallets = walletMetas.filter((meta) => !this.#openedWallets.has(meta.id)) const wallets = await Promise.all(closedWallets.map((meta) => this.openWallet(meta))) wallets.forEach((wallet) => this.#openedWallets.set(wallet.id, wallet)) - return [...this.#openedWallets.values()] + return {wallets: Array.from(this.#openedWallets.values()), metas: walletMetas} } async listWallets() { @@ -293,8 +321,10 @@ export class WalletManager { async removeWallet(id: string) { const deletedWalletIds = await this.deletedWalletIds() - this.#openedWallets.delete(id) await this.#rootStorage.setItem('deletedWalletIds', [...deletedWalletIds, id]) + + // can't update the walletInfo here cuz it might be in the middle of wallet syncing + this.#openedWallets.delete(id) } // TODO(ppershing): how should we deal with race conditions? diff --git a/apps/wallet-mobile/src/kernel/constants.ts b/apps/wallet-mobile/src/kernel/constants.ts index b584a8155c..25cab59b6e 100644 --- a/apps/wallet-mobile/src/kernel/constants.ts +++ b/apps/wallet-mobile/src/kernel/constants.ts @@ -59,6 +59,7 @@ export const configCurrencies = freeze({ }) export const time = freeze({ + oneSecond: 1e3, oneMinute: 60 * 1e3, fiveMinutes: 5 * 60 * 1e3, halfHour: 30 * 60 * 1e3, diff --git a/apps/wallet-mobile/src/kernel/env.ts b/apps/wallet-mobile/src/kernel/env.ts index bd637dd438..5b404e5d11 100644 --- a/apps/wallet-mobile/src/kernel/env.ts +++ b/apps/wallet-mobile/src/kernel/env.ts @@ -18,3 +18,6 @@ export const banxaTestWallet = getString('BANXA_TEST_WALLET') export const dappExplorerEnabled = Boolean(BuildConfig['DAPP_EXPLORER_ENABLED']) export const disableLogbox = Boolean(BuildConfig['DISABLE_LOGBOX']) + +const possibleLoggerFilter = getString('LOGGER_FILTER') +export const loggerFilter = possibleLoggerFilter ? new RegExp(possibleLoggerFilter) : null diff --git a/apps/wallet-mobile/src/kernel/logger/hooks/useSetupLogger.tsx b/apps/wallet-mobile/src/kernel/logger/hooks/useSetupLogger.tsx index 556e4aeda2..de6c4e1a2d 100644 --- a/apps/wallet-mobile/src/kernel/logger/hooks/useSetupLogger.tsx +++ b/apps/wallet-mobile/src/kernel/logger/hooks/useSetupLogger.tsx @@ -9,7 +9,7 @@ import {Sentry} from '../adapters/sentry' import {sentryAdapter} from '../adapters/sentry-transporter' import {logger} from '../logger' -export const useSetupLogger = () => { +export const useSetupLogger = (filter: RegExp | null = null) => { const [done, setDone] = React.useState(false) React.useEffect(() => { @@ -18,7 +18,10 @@ export const useSetupLogger = () => { const isEnabled = await getCrashReportsEnabled() logger.level = loggerLevel - if (isDev) logger.addTransport(devAdapter().transporter) + if (isDev) { + logger.addTransport(devAdapter().transporter) + logger.filter = filter + } if (isEnabled) { logger.enable() @@ -44,7 +47,7 @@ export const useSetupLogger = () => { setDone(true) } initLogger() - }, []) + }, [filter]) return done } diff --git a/apps/wallet-mobile/src/kernel/logger/logger.ts b/apps/wallet-mobile/src/kernel/logger/logger.ts index 6433fd52df..59cf5fcefe 100644 --- a/apps/wallet-mobile/src/kernel/logger/logger.ts +++ b/apps/wallet-mobile/src/kernel/logger/logger.ts @@ -16,6 +16,7 @@ class Logger implements LoggerManager { #enabled = false #trail: Array = [] + filter: RegExp | null = null level = LoggerLevel.Info readonly #transporters: LoggerTransporter[] = [] @@ -80,6 +81,7 @@ class Logger implements LoggerManager { private transport({level, message, metadata}: Pick) { if (!this.#enabled) return if (loggerHierarchy[level] > loggerHierarchy[this.level]) return + if (this.filter && !this.filter.test(JSON.stringify({message, metadata}))) return const timestamp = Date.now() const entry = {level, message, metadata, timestamp} diff --git a/apps/wallet-mobile/src/kernel/navigation.tsx b/apps/wallet-mobile/src/kernel/navigation.tsx index 775019eae7..261ed5fa80 100644 --- a/apps/wallet-mobile/src/kernel/navigation.tsx +++ b/apps/wallet-mobile/src/kernel/navigation.tsx @@ -142,8 +142,9 @@ export type WalletInitRoutes = { 'setup-wallet-about-recovery-phase': undefined 'setup-wallet-recovery-phrase-mnemonic': undefined 'setup-wallet-verify-recovery-phrase-mnemonic': undefined + 'setup-wallet-preparing-wallet': undefined } -export type WalletInitRouteNavigation = StackNavigationProp +export type SetupWalletRouteNavigation = StackNavigationProp export type ReceiveRoutes = { 'receive-ada-main': undefined @@ -183,7 +184,7 @@ export type ClaimRoutes = { } export type SwapTokenRoutes = { - 'swap-start-swap': undefined + 'swap-start-swap': NavigatorScreenParams 'swap-confirm-tx': undefined 'swap-select-sell-token': undefined 'swap-select-buy-token': undefined @@ -191,7 +192,6 @@ export type SwapTokenRoutes = { 'swap-select-pool': undefined 'swap-submitted-tx': {txId: string} 'swap-failed-tx': undefined - 'manage-wallets': undefined } export type SwapTokenRouteseNavigation = StackNavigationProp @@ -214,7 +214,6 @@ export type ExchangeRoutes = { 'exchange-result': undefined 'exchange-select-buy-provider': undefined 'exchange-select-sell-provider': undefined - 'manage-wallets': undefined } export type ExchangeRoutesNavigation = StackNavigationProp diff --git a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/SetupWalletNavigator.json b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/SetupWalletNavigator.json index 1b8cf454ec..fd6eeebba1 100644 --- a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/SetupWalletNavigator.json +++ b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/SetupWalletNavigator.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Add new wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 144, + "line": 151, "column": 21, - "index": 5055 + "index": 5302 }, "end": { - "line": 147, + "line": 154, "column": 3, - "index": 5157 + "index": 5404 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Create wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 148, + "line": 155, "column": 21, - "index": 5180 + "index": 5427 }, "end": { - "line": 151, + "line": 158, "column": 3, - "index": 5296 + "index": 5543 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Restore wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 152, + "line": 159, "column": 22, - "index": 5320 + "index": 5567 }, "end": { - "line": 155, + "line": 162, "column": 3, - "index": 5439 + "index": 5686 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Read-only Wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 156, + "line": 163, "column": 23, - "index": 5464 + "index": 5711 }, "end": { - "line": 159, + "line": 166, "column": 3, - "index": 5578 + "index": 5825 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!Verify read-only wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 160, + "line": 167, "column": 27, - "index": 5607 + "index": 5854 }, "end": { - "line": 163, + "line": 170, "column": 3, - "index": 5726 + "index": 5973 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Recovery phrase", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 164, + "line": 171, "column": 21, - "index": 5749 + "index": 5996 }, "end": { - "line": 167, + "line": 174, "column": 3, - "index": 5867 + "index": 6114 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Recovery phrase", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 168, + "line": 175, "column": 22, - "index": 5891 + "index": 6138 }, "end": { - "line": 171, + "line": 178, "column": 3, - "index": 6010 + "index": 6257 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!Verify restored wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 172, + "line": 179, "column": 29, - "index": 6041 + "index": 6288 }, "end": { - "line": 175, + "line": 182, "column": 3, - "index": 6155 + "index": 6402 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Wallet credentials", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 176, + "line": 183, "column": 26, - "index": 6183 + "index": 6430 }, "end": { - "line": 179, + "line": 186, "column": 3, - "index": 6310 + "index": 6557 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!Connect to Ledger Device", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 180, + "line": 187, "column": 21, - "index": 6333 + "index": 6580 }, "end": { - "line": 183, + "line": 190, "column": 3, - "index": 6460 + "index": 6707 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Connect to Ledger Device", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 184, + "line": 191, "column": 19, - "index": 6481 + "index": 6728 }, "end": { - "line": 187, + "line": 194, "column": 3, - "index": 6606 + "index": 6853 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!Save wallet", "file": "src/features/SetupWallet/SetupWalletNavigator.tsx", "start": { - "line": 188, + "line": 195, "column": 18, - "index": 6626 + "index": 6873 }, "end": { - "line": 191, + "line": 198, "column": 3, - "index": 6737 + "index": 6984 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.json b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.json index 6edb8733a3..ff9698e40e 100644 --- a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.json +++ b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/CheckNanoX/CheckNanoXScreen.json @@ -6,12 +6,12 @@ "start": { "line": 67, "column": 13, - "index": 2403 + "index": 2405 }, "end": { "line": 70, "column": 3, - "index": 2549 + "index": 2551 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.json b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.json index 38530c1ac2..2405a47714 100644 --- a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.json +++ b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ConnectNanoX/ConnectNanoXScreen.json @@ -6,12 +6,12 @@ "start": { "line": 82, "column": 13, - "index": 2905 + "index": 2907 }, "end": { "line": 85, "column": 3, - "index": 3077 + "index": 3079 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.json b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.json index 2818b0c274..2ab51a14ec 100644 --- a/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.json +++ b/apps/wallet-mobile/translations/messages/src/features/SetupWallet/legacy/ImportReadOnlyWallet/ImportReadOnlyWalletScreen.json @@ -6,12 +6,12 @@ "start": { "line": 63, "column": 13, - "index": 2157 + "index": 2159 }, "end": { "line": 66, "column": 3, - "index": 2331 + "index": 2333 } }, { @@ -21,12 +21,12 @@ "start": { "line": 67, "column": 9, - "index": 2342 + "index": 2344 }, "end": { "line": 70, "column": 3, - "index": 2486 + "index": 2488 } }, { @@ -36,12 +36,12 @@ "start": { "line": 71, "column": 9, - "index": 2497 + "index": 2499 }, "end": { "line": 74, "column": 3, - "index": 2673 + "index": 2675 } }, { @@ -51,12 +51,12 @@ "start": { "line": 75, "column": 14, - "index": 2689 + "index": 2691 }, "end": { "line": 78, "column": 3, - "index": 2822 + "index": 2824 } } ] \ No newline at end of file diff --git a/packages/common/src/utils/arrays.test.ts b/packages/common/src/utils/arrays.test.ts index 1aa2497c9b..55ffdc0a5c 100644 --- a/packages/common/src/utils/arrays.test.ts +++ b/packages/common/src/utils/arrays.test.ts @@ -4,7 +4,7 @@ describe('Array Utils', () => { describe('difference', () => { it('should return the difference of two arrays', () => { const a = [1, 2, 3, 4, 5] - const b = [2, 4, 6] + const b = [2, 4, 6, 7] const result = difference(a, b) expect(result).toEqual([1, 3, 5]) }) diff --git a/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.test.tsx b/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.test.tsx index 24af58e3fa..94fda1016e 100644 --- a/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.test.tsx +++ b/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.test.tsx @@ -124,6 +124,16 @@ describe('SetupWalletContext :: hooks', () => { expect(result.current.showRestoreWalletInfoModal).toBe(true) }) + test('walletIdChanged', () => { + const {result} = renderHook(() => useSetupWallet(), {wrapper}) + + act(() => { + result.current.walletIdChanged('1') + }) + + expect(result.current.walletId).toBe('1') + }) + test('showCreateWalletInfoModalChanged', () => { const {result} = renderHook(() => useSetupWallet(), {wrapper}) diff --git a/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.tsx b/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.tsx index d99858dee4..3d72917009 100644 --- a/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.tsx +++ b/packages/setup-wallet/src/translators/reactjs/provider/SetupWalletProvider.tsx @@ -74,6 +74,8 @@ export const SetupWalletProvider = ({ type: SetupWalletActionType.ShowCreateWalletInfoModalChanged, showCreateWalletInfoModal, }), + walletIdChanged: (walletId: SetupWalletState['walletId']) => + dispatch({type: SetupWalletActionType.WalletIdChanged, walletId}), }).current const context = React.useMemo( diff --git a/packages/setup-wallet/src/translators/reactjs/state/state.test.ts b/packages/setup-wallet/src/translators/reactjs/state/state.test.ts index a1727d5c24..6b500e66b3 100644 --- a/packages/setup-wallet/src/translators/reactjs/state/state.test.ts +++ b/packages/setup-wallet/src/translators/reactjs/state/state.test.ts @@ -59,6 +59,17 @@ describe('State Actions', () => { expect(state.networkId).toBe(action.networkId) }) + it('WalletIdChanged', () => { + const action: SetupWalletAction = { + type: SetupWalletActionType.WalletIdChanged, + walletId: '1', + } + + const state = setupWalletReducer(setupWalletDefaultState, action) + + expect(state.walletId).toBe(action.walletId) + }) + it('WalletImplementationIdChanged', () => { const action: SetupWalletAction = { type: SetupWalletActionType.WalletImplementationIdChanged, @@ -178,6 +189,7 @@ describe('State Actions', () => { useUSB: true, showCreateWalletInfoModal: true, showRestoreWalletInfoModal: true, + walletId: null, }, action, ) diff --git a/packages/setup-wallet/src/translators/reactjs/state/state.ts b/packages/setup-wallet/src/translators/reactjs/state/state.ts index a3ae8752c3..efe4082682 100644 --- a/packages/setup-wallet/src/translators/reactjs/state/state.ts +++ b/packages/setup-wallet/src/translators/reactjs/state/state.ts @@ -58,6 +58,10 @@ export const setupWalletReducer = ( draft.showRestoreWalletInfoModal = action.showRestoreWalletInfoModal return + case SetupWalletActionType.WalletIdChanged: + draft.walletId = action.walletId + return + case SetupWalletActionType.Reset: return setupWalletDefaultState @@ -82,6 +86,7 @@ export const setupWalletDefaultState: Readonly = freeze( useUSB: false, showRestoreWalletInfoModal: true, showCreateWalletInfoModal: true, + walletId: null, }, true, ) @@ -100,6 +105,7 @@ export type SetupWalletState = { useUSB: boolean showRestoreWalletInfoModal: boolean showCreateWalletInfoModal: boolean + walletId: string | null } export enum SetupWalletActionType { @@ -113,6 +119,7 @@ export enum SetupWalletActionType { HwDeviceInfoChanged = 'hwDeviceInfoChanged', SetUpTypeChanged = 'setUpTypeChanged', MnemonicTypeChanged = 'mnemonicTypeChanged', + WalletIdChanged = 'walletIdChanged', UseUSBChanged = 'useUSBChanged', Reset = 'reset', ShowRestoreWalletInfoModalChanged = 'showRestoreWalletInfoModalChanged', @@ -175,6 +182,10 @@ export type SetupWalletAction = type: SetupWalletActionType.ShowCreateWalletInfoModalChanged showCreateWalletInfoModal: SetupWalletState['showCreateWalletInfoModal'] } + | { + type: SetupWalletActionType.WalletIdChanged + walletId: SetupWalletState['walletId'] + } export type SetupWalletActions = { mnemonicChanged: (mnemonic: SetupWalletState['mnemonic']) => void @@ -192,6 +203,7 @@ export type SetupWalletActions = { setUpTypeChanged: (setUpType: SetupWalletState['setUpType']) => void mnemonicTypeChanged: (mnemonicType: SetupWalletState['mnemonicType']) => void useUSBChanged: (useUSB: SetupWalletState['useUSB']) => void + walletIdChanged: (walletId: SetupWalletState['walletId']) => void reset: () => void showRestoreWalletInfoModalChanged: ( showRestoreWalletInfoModal: boolean, @@ -217,6 +229,7 @@ export const setupWalletInitialContext: SetupWalletContext = freeze( reset: missingInit, showRestoreWalletInfoModalChanged: missingInit, showCreateWalletInfoModalChanged: missingInit, + walletIdChanged: missingInit, }, true, ) diff --git a/packages/theme/src/atoms/atoms.ts b/packages/theme/src/atoms/atoms.ts index 12f691aa07..0c239b345d 100644 --- a/packages/theme/src/atoms/atoms.ts +++ b/packages/theme/src/atoms/atoms.ts @@ -16,7 +16,7 @@ const fontFamily = { default: 'monospace', }), }, -} +} as const const size = { h1: { @@ -183,7 +183,7 @@ const typograpghy = { text_right: { textAlign: 'right', }, -} +} as const const padding = { p_0: {padding: tokens.space.none},