diff --git a/app/components/CreateWalletStepIndicator.tsx b/app/components/CreateWalletStepIndicator.tsx index 6b102744a0..015f92170b 100644 --- a/app/components/CreateWalletStepIndicator.tsx +++ b/app/components/CreateWalletStepIndicator.tsx @@ -78,7 +78,7 @@ export function CreateWalletStepIndicator (props: StepIndicatorProps): JSX.Eleme {following()} - + {descriptions()} diff --git a/app/components/OceanInterface/OceanInterface.tsx b/app/components/OceanInterface/OceanInterface.tsx index 2dd8f35923..b9e4784712 100644 --- a/app/components/OceanInterface/OceanInterface.tsx +++ b/app/components/OceanInterface/OceanInterface.tsx @@ -111,7 +111,11 @@ export function OceanInterface (): JSX.Element | null { }) broadcastTransaction(transaction.tx, client) .then(async () => { - setTxUrl(getTransactionUrl(transaction.tx.txId)) + try { + setTxUrl(getTransactionUrl(transaction.tx.txId)) + } catch (e) { + Logging.error(e) + } setTx({ ...transaction, title: translate('screens/OceanInterface', 'Waiting for confirmation') @@ -133,6 +137,7 @@ export function OceanInterface (): JSX.Element | null { .catch((e: Error) => { const errMsg = `${e.message}. Txid: ${transaction.tx.txId}` setError(new Error(errMsg)) + Logging.error(e) }) .finally(() => { dispatch(ocean.actions.popTransaction()) diff --git a/app/contexts/DeFiScanContext.tsx b/app/contexts/DeFiScanContext.tsx index d7eed3a2a0..532469de7d 100644 --- a/app/contexts/DeFiScanContext.tsx +++ b/app/contexts/DeFiScanContext.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useMemo, createContext } from 'react' +import React, { createContext, useContext, useMemo } from 'react' import { EnvironmentNetwork } from '../environment' import { useNetworkContext } from './NetworkContext' @@ -31,7 +31,7 @@ export function DeFiScanProvider (props: React.PropsWithChildren): JSX.Elem } function getTxURLByNetwork (network: EnvironmentNetwork, txid: string): string { - const baseUrl = new URL(`https://defiscan.live/transactions/${txid}`) + let baseUrl = `https://defiscan.live/transactions/${txid}` switch (network) { case EnvironmentNetwork.MainNet: @@ -39,12 +39,12 @@ function getTxURLByNetwork (network: EnvironmentNetwork, txid: string): string { break case EnvironmentNetwork.TestNet: - baseUrl.searchParams.set('network', EnvironmentNetwork.TestNet) + baseUrl = `${baseUrl}?network=${EnvironmentNetwork.TestNet}` break case EnvironmentNetwork.LocalPlayground: case EnvironmentNetwork.RemotePlayground: - baseUrl.searchParams.set('network', EnvironmentNetwork.RemotePlayground) + baseUrl = `${baseUrl}?network=${EnvironmentNetwork.RemotePlayground}` break } diff --git a/app/screens/WalletNavigator/WalletNavigator.tsx b/app/screens/WalletNavigator/WalletNavigator.tsx index cd5fdd42cb..8a6fe6d245 100644 --- a/app/screens/WalletNavigator/WalletNavigator.tsx +++ b/app/screens/WalletNavigator/WalletNavigator.tsx @@ -14,6 +14,8 @@ import { VerifyMnemonicWallet } from './screens/CreateWallet/VerifyMnemonicWalle import { Onboarding } from './screens/Onboarding' import { RestoreMnemonicWallet } from './screens/RestoreWallet/RestoreMnemonicWallet' +type PinCreationType = 'create' | 'restore' + export interface WalletParamList { WalletOnboardingScreen: undefined CreateMnemonicWallet: undefined @@ -24,10 +26,12 @@ export interface WalletParamList { PinCreation: { pinLength: 4 | 6 words: string[] + type: PinCreationType } PinConfirmation: { pin: string words: string[] + type: PinCreationType } [key: string]: undefined | object diff --git a/app/screens/WalletNavigator/screens/CreateWallet/PinConfirmationScreen.tsx b/app/screens/WalletNavigator/screens/CreateWallet/PinConfirmationScreen.tsx index 90bd15453d..ace6e559c1 100644 --- a/app/screens/WalletNavigator/screens/CreateWallet/PinConfirmationScreen.tsx +++ b/app/screens/WalletNavigator/screens/CreateWallet/PinConfirmationScreen.tsx @@ -4,7 +4,11 @@ import { ActivityIndicator, ScrollView } from 'react-native' import { Logging } from '../../../../api' import { MnemonicEncrypted } from '../../../../api/wallet' import { Text, View } from '../../../../components' -import { CREATE_STEPS, CreateWalletStepIndicator } from '../../../../components/CreateWalletStepIndicator' +import { + CREATE_STEPS, + CreateWalletStepIndicator, + RESTORE_STEPS +} from '../../../../components/CreateWalletStepIndicator' import { PinTextInput } from '../../../../components/PinTextInput' import { useNetworkContext } from '../../../../contexts/NetworkContext' import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext' @@ -16,7 +20,7 @@ type Props = StackScreenProps export function PinConfirmation ({ route }: Props): JSX.Element { const { network } = useNetworkContext() - const { pin, words } = route.params + const { pin, words, type } = route.params const { setWallet } = useWalletPersistenceContext() const [newPin, setNewPin] = useState('') @@ -26,6 +30,7 @@ export function PinConfirmation ({ route }: Props): JSX.Element { function verifyPin (input: string): void { if (input.length !== pin.length) return if (input !== pin) { + setNewPin('') setInvalid(true) return } else { @@ -46,8 +51,8 @@ export function PinConfirmation ({ route }: Props): JSX.Element { return ( @@ -73,7 +78,7 @@ export function PinConfirmation ({ route }: Props): JSX.Element { } { invalid && ( - + {translate('screens/PinConfirmation', 'Wrong passcode entered')} ) diff --git a/app/screens/WalletNavigator/screens/CreateWallet/PinCreationScreen.tsx b/app/screens/WalletNavigator/screens/CreateWallet/PinCreationScreen.tsx index 4cc8dc3989..eea277a6df 100644 --- a/app/screens/WalletNavigator/screens/CreateWallet/PinCreationScreen.tsx +++ b/app/screens/WalletNavigator/screens/CreateWallet/PinCreationScreen.tsx @@ -5,7 +5,11 @@ import React, { useState } from 'react' import { ScrollView } from 'react-native' import { Text, View } from '../../../../components' import { Button } from '../../../../components/Button' -import { CREATE_STEPS, CreateWalletStepIndicator } from '../../../../components/CreateWalletStepIndicator' +import { + CREATE_STEPS, + CreateWalletStepIndicator, + RESTORE_STEPS +} from '../../../../components/CreateWalletStepIndicator' import { PinTextInput } from '../../../../components/PinTextInput' import { tailwind } from '../../../../tailwind' import { translate } from '../../../../translations' @@ -15,20 +19,23 @@ type Props = StackScreenProps export function PinCreationScreen ({ route }: Props): JSX.Element { const navigation = useNavigation>() - const { pinLength, words } = route.params + const { pinLength, words, type } = route.params const [newPin, setNewPin] = useState('') return ( - + {translate('screens/PinCreation', 'Well done! Your wallet is created. Keep your wallet private and secure by creating a passcode for it.')} + >{translate('screens/PinCreation', `Well done! Your wallet is ${type === 'create' ? 'created' : 'restored'}. Keep your wallet private and secure by creating a passcode for it.`)} @@ -45,7 +52,7 @@ export function PinCreationScreen ({ route }: Props): JSX.Element { title='create-pin' disabled={newPin.length !== pinLength} onPress={() => { - navigation.navigate('PinConfirmation', { words, pin: newPin }) + navigation.navigate('PinConfirmation', { words, pin: newPin, type }) }} /> diff --git a/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx b/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx index 931e685917..e25c97e946 100644 --- a/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx +++ b/app/screens/WalletNavigator/screens/CreateWallet/VerifyMnemonicWallet.tsx @@ -47,12 +47,17 @@ export function VerifyMnemonicWallet ({ route, navigation }: Props): JSX.Element setRandomWords([...randomWords]) }, [JSON.stringify(recoveryWords)]) + function navigateToPinCreation (): void { + navigation.navigate('PinCreation', { + pinLength: HARDCODED_PIN_LENGTH, + words: recoveryWords, + type: 'create' + }) + } + function onVerify (): void { if (recoveryWords.join(' ') === selectedWords.join(' ')) { - navigation.navigate('PinCreation', { - pinLength: HARDCODED_PIN_LENGTH, - words: recoveryWords - }) + navigateToPinCreation() } else { if (Platform.OS === 'web') { navigation.navigate('CreateMnemonicWallet') @@ -74,10 +79,7 @@ export function VerifyMnemonicWallet ({ route, navigation }: Props): JSX.Element function debugBypass (): void { if (getEnvironment().debug) { - navigation.navigate('PinCreation', { - pinLength: HARDCODED_PIN_LENGTH, - words: recoveryWords - }) + navigateToPinCreation() } } diff --git a/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx b/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx index c5c788a879..f1ef9e72a0 100644 --- a/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx +++ b/app/screens/WalletNavigator/screens/RestoreWallet/RestoreMnemonicWallet.tsx @@ -1,22 +1,21 @@ import { validateMnemonicSentence } from '@defichain/jellyfish-wallet-mnemonic' +import { NavigationProp, useNavigation } from '@react-navigation/native' import * as React from 'react' import { createRef, useEffect, useState } from 'react' import { Controller, useForm } from 'react-hook-form' import { Alert, TextInput } from 'react-native' import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view' -import { MnemonicUnprotected } from '../../../../api/wallet/provider/mnemonic_unprotected' import { Text, View } from '../../../../components' import { Button } from '../../../../components/Button' +import { CreateWalletStepIndicator, RESTORE_STEPS } from '../../../../components/CreateWalletStepIndicator' import { SectionTitle } from '../../../../components/SectionTitle' -import { useNetworkContext } from '../../../../contexts/NetworkContext' -import { useWalletPersistenceContext } from '../../../../contexts/WalletPersistenceContext' import { tailwind } from '../../../../tailwind' import { translate } from '../../../../translations' import LoadingScreen from '../../../LoadingNavigator/LoadingScreen' +import { WalletParamList } from '../../WalletNavigator' export function RestoreMnemonicWallet (): JSX.Element { - const { network } = useNetworkContext() - const { setWallet } = useWalletPersistenceContext() + const navigation = useNavigation>() const { control, formState: { isValid }, getValues } = useForm({ mode: 'onChange' }) const [recoveryWords] = useState(Array.from(Array(24), (v, i) => i + 1)) const [isSubmitting, setIsSubmitting] = useState(false) @@ -38,7 +37,11 @@ export function RestoreMnemonicWallet (): JSX.Element { const words = Object.values(getValues()) if (isValid && validateMnemonicSentence(words)) { setIsSubmitting(false) - await setWallet(MnemonicUnprotected.toData(words, network)) + navigation.navigate('PinCreation', { + words, + pinLength: 6, + type: 'restore' + }) } else { setIsSubmitting(false) Alert.alert( @@ -52,16 +55,23 @@ export function RestoreMnemonicWallet (): JSX.Element { } return ( - - + + + {translate('screens/RestoreWallet', 'Please provide your 24 recovery words to regain access to your wallet.')} - + + + { recoveryWords.map((order) => ( { cy.getByTestID('verify_words_button').click() }) - it('should be able to set pincode', function () { + it('should be able to verify and set pincode', function () { cy.getByTestID('pin_input').type('000000') cy.getByTestID('create_pin_button').click() + cy.getByTestID('pin_confirm_input').type('777777').wait(5000) + cy.getByTestID('wrong_passcode_text').should('exist') cy.getByTestID('pin_confirm_input').type('000000') }) @@ -58,7 +60,10 @@ context('wallet/createmnemonic', () => { cy.getByTestID(`recover_word_${index + 1}`).should('have.css', 'color', 'rgb(0, 0, 0)') }) cy.getByTestID('recover_wallet_button').should('not.have.attr', 'disabled') - cy.getByTestID('recover_wallet_button').click().wait(2000) + cy.getByTestID('recover_wallet_button').click() + cy.getByTestID('pin_input').type('000000') + cy.getByTestID('create_pin_button').click() + cy.getByTestID('pin_confirm_input').type('000000') cy.getByTestID('balances_list').should('exist') }) }) diff --git a/cypress/integration/functional/onboarding/restore.spec.ts b/cypress/integration/functional/onboarding/restore.spec.ts index 25f66db18b..2285f748a3 100644 --- a/cypress/integration/functional/onboarding/restore.spec.ts +++ b/cypress/integration/functional/onboarding/restore.spec.ts @@ -32,6 +32,12 @@ context('wallet/recover', () => { it('should be able to submit form', function () { cy.getByTestID('recover_wallet_button').should('not.have.attr', 'disabled') cy.getByTestID('recover_wallet_button').click().wait(2000) + }) + + it('should be able to set pincode', function () { + cy.getByTestID('pin_input').type('000000') + cy.getByTestID('create_pin_button').click() + cy.getByTestID('pin_confirm_input').type('000000') cy.getByTestID('balances_list').should('exist') }) })