Skip to content

Commit

Permalink
fix(wallet-setup): duplicated wallet warning (#3194)
Browse files Browse the repository at this point in the history
  • Loading branch information
banklesss authored Apr 17, 2024
1 parent 91d3986 commit 829e0ec
Show file tree
Hide file tree
Showing 8 changed files with 518 additions and 319 deletions.
2 changes: 1 addition & 1 deletion apps/wallet-mobile/src/WalletNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import {GovernanceNavigator} from './features/Staking/Governance'
import {ToggleAnalyticsSettingsNavigator} from './features/ToggleAnalyticsSettings'
import {useSelectedWallet} from './features/WalletManager/Context/SelectedWalletContext'
import {SelectWalletFromList} from './features/WalletManager/SelectWalletFromList'
import {SelectWalletFromList} from './features/WalletManager/SelectWalletFromList/SelectWalletFromListScreen'
import {useMetrics} from './metrics/metricsManager'
import {hideTabBarForRoutes, WalletStackRoutes, WalletTabRoutes} from './navigation'
import {defaultStackNavigationOptions} from './navigation'
Expand Down
16 changes: 16 additions & 0 deletions apps/wallet-mobile/src/features/SetupWallet/common/useStrings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ export const useStrings = () => {
choose24WordsMnemonicTitle: intl.formatMessage(messages.choose24WordsMnemonicTitle),
restoreWalletScreenTitle: (options: {b: (content: React.ReactNode[]) => React.ReactNode}) =>
intl.formatMessage(messages.restoreWalletScreenTitle, {...options}),
restoreDuplicatedWalletModalTitle: intl.formatMessage(messages.restoreDuplicatedWalletModalTitle),
restoreDuplicatedWalletModalText: intl.formatMessage(messages.restoreDuplicatedWalletModalText),
restoreDuplicatedWalletModalButton: intl.formatMessage(messages.restoreDuplicatedWalletModalButton),
}).current
}

Expand Down Expand Up @@ -395,5 +398,18 @@ export const messages = Object.freeze(
id: 'components.walletinit.restorewallet.restorewalletscreen.restoreWalletScreenTitle',
defaultMessage: '!!!Add the recovery phrase you received upon your wallet creation process.',
},
restoreDuplicatedWalletModalTitle: {
id: 'components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalTitle',
defaultMessage: '!!!This wallet is already added',
},
restoreDuplicatedWalletModalText: {
id: 'components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalText',
defaultMessage:
'!!!This wallet already exist on your device, You can open it or go back and restore another wallet.',
},
restoreDuplicatedWalletModalButton: {
id: 'components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalButton',
defaultMessage: '!!!Open wallet',
},
}),
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as React from 'react'
import {useIntl} from 'react-intl'
import {
InteractionManager,
Keyboard,
Linking,
ScrollView,
StyleSheet,
Expand Down Expand Up @@ -38,12 +37,14 @@ import {
validateWalletName,
} from '../../../../yoroi-wallets/utils'
import {debugWalletInfo, features} from '../../..'
import {useSetSelectedWallet, useSetSelectedWalletMeta} from '../../../WalletManager/Context'
import {useSetSelectedWallet} from '../../../WalletManager/Context/SelectedWalletContext'
import {useSetSelectedWalletMeta} from '../../../WalletManager/Context/SelectedWalletMetaContext'
import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase'
import {YoroiZendeskLink} from '../../common/contants'
import {LearnMoreButton} from '../../common/LearnMoreButton/LearnMoreButton'
import {StepperProgress} from '../../common/StepperProgress/StepperProgress'
import {useStrings} from '../../common/useStrings'
import {Info as InfoIllustration} from '../../illustrations/Info'

const useSizeModal = () => {
const HEIGHT_SCREEN = useWindowDimensions().height
Expand Down Expand Up @@ -165,7 +166,6 @@ export const WalletDetailsScreen = () => {
}, [createWallet, mnemonic, name, networkId, password, track, walletImplementationId])

const showModalTipsPassword = () => {
Keyboard.dismiss()
openModal(
strings.walletDetailsModalTitle,
<View style={styles.modal}>
Expand Down Expand Up @@ -204,7 +204,6 @@ export const WalletDetailsScreen = () => {
}

const showModalTipsPlateNumber = () => {
Keyboard.dismiss()
openModal(
strings.walletDetailsModalTitle,
<View style={styles.modal}>
Expand Down Expand Up @@ -246,13 +245,13 @@ export const WalletDetailsScreen = () => {
<View>
<StepperProgress currentStep={4} currentStepTitle={strings.stepWalletDetails} totalSteps={4} />

<Text style={styles.title}>
{strings.walletDetailsTitle(bold)}
<View style={styles.info}>
<Text style={styles.title}>{strings.walletDetailsTitle(bold)}</Text>

<TouchableOpacity onPress={showModalTipsPassword}>
<Icon.Info size={28} />
<InfoIllustration />
</TouchableOpacity>
</Text>
</View>

<Space height="xl" />

Expand Down Expand Up @@ -311,15 +310,13 @@ export const WalletDetailsScreen = () => {

<Space width="s" />

<Text style={styles.plateNumber}>
{plate.accountPlate.TextPart}
<Text style={styles.plateNumber}>{plate.accountPlate.TextPart}</Text>

<Space width="s" />
<Space width="s" />

<TouchableOpacity onPress={showModalTipsPlateNumber}>
<Icon.Info size={28} />
</TouchableOpacity>
</Text>
<TouchableOpacity onPress={showModalTipsPlateNumber}>
<InfoIllustration />
</TouchableOpacity>
</View>
</View>

Expand Down Expand Up @@ -353,6 +350,9 @@ const useStyles = () => {
justifyContent: 'space-between',
backgroundColor: theme.color['white-static'],
},
info: {
flexDirection: 'row',
},
modal: {
flex: 1,
},
Expand All @@ -374,9 +374,14 @@ const useStyles = () => {
},
checksum: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
textAlignVertical: 'center',
},
walletChecksum: {
width: 24,
height: 24,
},
walletChecksum: {width: 24, height: 24},
})

return {styles} as const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import {
validateWalletName,
} from '../../../../yoroi-wallets/utils'
import {debugWalletInfo, features} from '../../..'
import {useSetSelectedWallet, useSetSelectedWalletMeta} from '../../../WalletManager/Context'
import {useSetSelectedWallet} from '../../../WalletManager/Context/SelectedWalletContext'
import {useSetSelectedWalletMeta} from '../../../WalletManager/Context/SelectedWalletMetaContext'
import {CardAboutPhrase} from '../../common/CardAboutPhrase/CardAboutPhrase'
import {YoroiZendeskLink} from '../../common/contants'
import {LearnMoreButton} from '../../common/LearnMoreButton/LearnMoreButton'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import {walletChecksum} from '@emurgo/cip4-js'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {NetworkError} from '@yoroi/common'
import {useSetupWallet} from '@yoroi/setup-wallet'
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {StyleSheet, Text, View} from 'react-native'
import {useIntl} from 'react-intl'
import {InteractionManager, StyleSheet, Text, View} from 'react-native'
import {ScrollView} from 'react-native-gesture-handler'
import {SafeAreaView} from 'react-native-safe-area-context'

import {Button, KeyboardAvoidingView} from '../../../../components'
import {Button, Icon, KeyboardAvoidingView, useModal} from '../../../../components'
import {Space} from '../../../../components/Space/Space'
import {showErrorDialog} from '../../../../dialogs'
import {errorMessages} from '../../../../i18n/global-messages'
import {useMetrics} from '../../../../metrics/metricsManager'
import {WalletInitRouteNavigation} from '../../../../navigation'
import {useWalletNavigation, WalletInitRouteNavigation} from '../../../../navigation'
import {isEmptyString} from '../../../../utils'
import {useWalletManager} from '../../../../wallet-manager/WalletManagerContext'
import {InvalidState} from '../../../../yoroi-wallets/cardano/errors'
import {makeKeys} from '../../../../yoroi-wallets/cardano/shelley/makeKeys'
import {useOpenWallet, usePlate, useWalletMetas} from '../../../../yoroi-wallets/hooks'
import {useSetSelectedWallet} from '../../../WalletManager/Context/SelectedWalletContext'
import {useSetSelectedWalletMeta} from '../../../WalletManager/Context/SelectedWalletMetaContext'
import {MnemonicInput} from '../../common/MnemonicInput'
import {StepperProgress} from '../../common/StepperProgress/StepperProgress'
import {useStrings} from '../../common/useStrings'
Expand All @@ -23,6 +33,9 @@ export const RestoreWalletScreen = () => {
const navigation = useNavigation<WalletInitRouteNavigation>()
const {publicKeyHexChanged, mnemonicChanged, mnemonicType} = useSetupWallet()
const {track} = useMetrics()
const walletManager = useWalletManager()
const {walletMetas} = useWalletMetas(walletManager)
const {openModal} = useModal()

const strings = useStrings()

Expand All @@ -35,6 +48,61 @@ export const RestoreWalletScreen = () => {
}, [mnemonicType, track]),
)

const intl = useIntl()
const {navigateToTxHistory} = useWalletNavigation()
const selectWalletMeta = useSetSelectedWalletMeta()
const selectWallet = useSetSelectedWallet()

const {openWallet} = useOpenWallet({
onSuccess: ([wallet, walletMeta]) => {
selectWalletMeta(walletMeta)
selectWallet(wallet)
navigateToTxHistory()
},
onError: (error) => {
InteractionManager.runAfterInteractions(() => {
return error instanceof InvalidState
? showErrorDialog(errorMessages.walletStateInvalid, intl)
: error instanceof NetworkError
? showErrorDialog(errorMessages.networkError, intl)
: showErrorDialog(errorMessages.generalError, intl, {message: error.message})
})
},
})

const handleOnNext = React.useCallback(async () => {
const {accountPubKeyHex} = await makeKeys({mnemonic})
const checksum = walletChecksum(accountPubKeyHex)

const duplicatedWalletMeta = walletMetas?.find((walletMeta) => walletMeta.checksum.TextPart === checksum.TextPart)

if (duplicatedWalletMeta) {
openModal(
strings.restoreDuplicatedWalletModalTitle,
<Modal
walletName={duplicatedWalletMeta.name}
publicKeyHex={accountPubKeyHex}
onPress={() => openWallet(duplicatedWalletMeta)}
/>,
)

return
}

mnemonicChanged(mnemonic)
publicKeyHexChanged(accountPubKeyHex)
navigation.navigate('setup-wallet-restore-details')
}, [
mnemonic,
mnemonicChanged,
navigation,
openModal,
openWallet,
publicKeyHexChanged,
strings.restoreDuplicatedWalletModalTitle,
walletMetas,
])

return (
<SafeAreaView edges={['left', 'right', 'bottom']} style={styles.root}>
<KeyboardAvoidingView style={{flex: 1}}>
Expand All @@ -57,21 +125,55 @@ export const RestoreWalletScreen = () => {
title={strings.next}
style={styles.button}
disabled={isEmptyString(mnemonic)}
onPress={async () => {
const {accountPubKeyHex} = await makeKeys({mnemonic})
mnemonicChanged(mnemonic)
publicKeyHexChanged(accountPubKeyHex)
navigation.navigate('setup-wallet-restore-details')
}}
onPress={handleOnNext}
/>

<Space height="s" />
</View>
</KeyboardAvoidingView>
</SafeAreaView>
)
}

const Modal = ({
onPress,
publicKeyHex,
walletName,
}: {
onPress: () => void
publicKeyHex: string
walletName: string
}) => {
const {styles} = useStyles()
const strings = useStrings()
const {networkId} = useSetupWallet()
const plate = usePlate({networkId, publicKeyHex})

return (
<View style={styles.modal}>
<Text style={styles.modalText}>{strings.restoreDuplicatedWalletModalText}</Text>

<Space height="l" />

<View style={styles.checksum}>
<Icon.WalletAccount iconSeed={plate.accountPlate.ImagePart} style={styles.walletChecksum} />

<Space width="s" />

<View>
<Text style={styles.plateName}>{walletName}</Text>

<Text style={styles.plateText}>{plate.accountPlate.TextPart}</Text>
</View>
</View>

<Space fill />

<Button title={strings.restoreDuplicatedWalletModalButton} style={styles.button} onPress={onPress} />

<Space height="xl" />
</View>
)
}

const useBold = () => {
const {styles} = useStyles()

Expand Down Expand Up @@ -99,6 +201,34 @@ const useStyles = () => {
padding: {
...theme.padding['l'],
},
checksum: {
flexDirection: 'row',
alignItems: 'center',
textAlignVertical: 'center',
},
walletChecksum: {
width: 38,
height: 38,
borderRadius: 8,
},
modalText: {
...theme.typography['body-1-l-regular'],
color: theme.color.gray[900],
lineHeight: 24,
},
plateText: {
...theme.typography['body-3-s-regular'],
color: theme.color.gray[600],
textAlign: 'center',
justifyContent: 'center',
},
plateName: {
...theme.typography['body-2-m-medium'],
color: theme.color.gray[900],
},
modal: {
flex: 1,
},
})

const colors = {
Expand Down

This file was deleted.

5 changes: 4 additions & 1 deletion apps/wallet-mobile/src/i18n/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -588,14 +588,17 @@
"components.walletinit.restorewallet.restorewalletscreen.instructions": "To restore your wallet, please provide the {mnemonicLength}-word recovery phrase generated when you created your wallet for the first time.",
"components.walletinit.restorewallet.restorewalletscreen.invalidchecksum": "Incorrect recovery phrase. Try again",
"components.walletinit.restorewallet.restorewalletscreen.validchecksum": "The recovery phrase is verified",
"components.walletinit.restorewallet.restorewalletscreen.restoreWalletScreenTitle": "Add the <b>recovery phrase</b> you received upon your wallet creation process.",
"components.walletinit.restorewallet.restorewalletscreen.stepRestoreWalletScreen": "Enter recovery phrase",
"components.walletinit.restorewallet.restorewalletscreen.mnemonicInputLabel": "Recovery phrase",
"components.walletinit.restorewallet.restorewalletscreen.restoreButton": "Restore wallet",
"components.walletinit.restorewallet.restorewalletscreen.title": "Restore wallet",
"components.walletinit.restorewallet.restorewalletscreen.toolong": "Phrase is too long.",
"components.walletinit.restorewallet.restorewalletscreen.tooshort": "Phrase is too short.",
"components.walletinit.restorewallet.restorewalletscreen.unknowwords": "{wordlist} {cnt, plural, one {is} other {are}} invalid",
"components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalText": "This wallet already exist on your device, You can open it or go back and restore another wallet.",
"components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalTitle": "This wallet is already added",
"components.walletinit.restorewallet.restorewalletscreen.restoreDuplicatedWalletModalButton": "Open wallet",
"components.walletinit.restorewallet.restorewalletscreen.restoreWalletScreenTitle": "Add the <b>recovery phrase</b> you received upon your wallet creation process.",
"components.walletinit.restorewallet.upgradeconfirmmodal.balanceLabel": "Recovered balance",
"components.walletinit.restorewallet.upgradeconfirmmodal.finalBalanceLabel": "Final balance",
"components.walletinit.restorewallet.upgradeconfirmmodal.fromLabel": "From",
Expand Down
Loading

0 comments on commit 829e0ec

Please sign in to comment.