Import wallet from backup and fixes

This commit is contained in:
minibits-cash
2024-10-11 16:21:07 +02:00
parent 3d68057699
commit 5bb8af10da
13 changed files with 192 additions and 133 deletions
+3 -2
View File
@@ -68,8 +68,9 @@ function App(props: AppProps) {
// This runs after the root store has been initialized and rehydrated from storage.
// Creates and opens a sqlite database that stores transactions history and user settings.
// It triggers db migrations if database version has changed.
Database.getDatabaseVersion()
// It triggers db migrations if database version has changed.
const db = Database.getInstance()
Database.getDatabaseVersion(db)
// Syncs userSettings store with the database (needed?)
userSettingsStore.loadUserSettings()
+1 -1
View File
@@ -309,7 +309,7 @@
"changeWalletaddress": "Change wallet address",
"changeWalletaddressSubtext": "Change unique wallet address. Select one of randomly generated or choose your own."
},
"profileToRecoverDesc": "This is the wallet address linked to your seed. If you press Complete, your wallet profile will reset to above seed and address.",
"profileToRecoverDesc": "This is the wallet address linked to your seed. If you continue, your wallet profile will reset to above seed and address.",
"pushNotifications": "Push notifications",
"qr": {
"fail": "Could not display QR code, use option to copy or send the token to the payee wallet address."
+1 -1
View File
@@ -46,7 +46,7 @@ export const RelaysStoreModel = types
relay.url = normalized
if(self.alreadyExists(relay.url)) {
log.warn('[addRelay] Relay already exists', {relay})
log.info('[addRelay] Relay already exists', {relay})
return
}
+2 -3
View File
@@ -16,9 +16,8 @@ import {
} from 'mobx-state-tree'
import { debounce } from "lodash"
import * as Sentry from '@sentry/react-native'
import RNExitApp from 'react-native-exit-app'
import type {RootStore} from '../RootStore'
import {KeyChain, MinibitsClient, MMKVStorage, NostrClient} from '../../services'
import {KeyChain, MinibitsClient, MMKVStorage} from '../../services'
import {Database} from '../../services'
import { log } from '../../services/logService'
import { rootStoreModelVersion } from '../RootStore'
@@ -62,7 +61,7 @@ export async function setupRootStore(rootStore: RootStore) {
log.trace('[setupRootStore]', `Loading ${dataSize.toLocaleString()} bytes of state from MMKV took ${(mmkvLoaded - start).toLocaleString()} ms.`)
log.trace({restoredState})
// log.trace({restoredState})
applySnapshot(rootStore, restoredState)
+1 -1
View File
@@ -60,7 +60,7 @@ export const BackupOptionsScreen: FC<SettingsStackScreenProps<'BackupOptions'>>
tx="backupScreen.mnemonicTitle"
subTx="backupScreen.mnemonicDescription"
leftIcon='faSeedling'
leftIconColor={colors.palette.blue200}
leftIconColor={colors.palette.orange400}
leftIconInverse={true}
style={$item}
onPress={gotoMnemonic}
+10 -15
View File
@@ -35,6 +35,8 @@ import {MMKVStorage} from '../services'
import {maxTransactionsInModel} from '../models/TransactionsStore'
import { LogLevel } from '../services/log/logTypes'
import { getSnapshot } from 'mobx-state-tree'
import { delay } from '../utils/delay'
import RNExitApp from 'react-native-exit-app'
// refresh
@@ -50,6 +52,7 @@ export const DeveloperScreen: FC<SettingsStackScreenProps<'Developer'>> = observ
const [isLoading, setIsLoading] = useState(false)
const [rnVersion, setRnVersion] = useState<string>('')
const [walletStateSize, setWalletStateSize] = useState<number>(0)
const [dbVersion, setDbVersion] = useState<number>(0)
const [isLogLevelSelectorVisible, setIsLogLevelSelectorVisible] = useState<boolean>(false)
const [selectedLogLevel, setSelectedLogLevel] = useState<LogLevel>(userSettingsStore.logLevel)
const [error, setError] = useState<AppError | undefined>()
@@ -62,6 +65,10 @@ export const DeveloperScreen: FC<SettingsStackScreenProps<'Developer'>> = observ
// log.info('[SNAPSHOT]', {snapshot})
const stateSize = Buffer.byteLength(JSON.stringify(snapshot), 'utf8')
const db = Database.getInstance()
const {version} = Database.getDatabaseVersion(db)
setDbVersion(version)
setWalletStateSize(stateSize)
setRnVersion(rn)
}
@@ -143,6 +150,8 @@ export const DeveloperScreen: FC<SettingsStackScreenProps<'Developer'>> = observ
Database.getInstance()
setIsLoading(false)
setInfo(translate("factoryResetSuccess"))
await delay(1000)
RNExitApp.exitApp()
} catch (e: any) {
handleError(e)
}
@@ -187,20 +196,6 @@ export const DeveloperScreen: FC<SettingsStackScreenProps<'Developer'>> = observ
bottomSeparator={true}
onPress={toggleLogLevelSelector}
/>
{/*<ListItem
tx="developerScreen.transactions"
subText={translate(
'developerScreen.transactionsDescription',
{count: transactionsStore.count},
)}
leftIcon='faDownload'
leftIconColor={colors.palette.iconYellow300}
leftIconInverse={true}
RightComponent={<View style={$rightContainer} />}
style={$item}
bottomSeparator={true}
onPress={syncTransactionsFromDb}
/>*/}
<ListItem
tx="showOnboarding"
subTx="showOnboardingDesc"
@@ -223,7 +218,7 @@ export const DeveloperScreen: FC<SettingsStackScreenProps<'Developer'>> = observ
subText={`Environment: ${APP_ENV}
Native version: ${NATIVE_VERSION_ANDROID}
JS Bundle version: ${JS_BUNDLE_VERSION}
DB version: ${Database.getDatabaseVersion().version}
DB version: ${dbVersion}
State size: ${walletStateSize.toLocaleString()} bytes
React Native: ${rnVersion}
Commit: ${COMMIT}
+11 -1
View File
@@ -64,8 +64,11 @@ export const ExportBackupScreen: FC<ExportBackupScreenProps> =
useEffect(() => {
const loadProofs = async () => {
setIsLoading(true)
// log.trace('[loadProofs]', {proofs: proofsStore.proofs})
// full refresh of proofs from DB in case the state is broken
await proofsStore.loadProofsFromDatabase()
// log.trace('[loadProofs]', {refreshedProofs: proofsStore.proofs})
setIsLoading(false)
}
@@ -117,7 +120,14 @@ export const ExportBackupScreen: FC<ExportBackupScreenProps> =
}
if(isEcashInBackup) {
exportedProofsStore = getSnapshot(proofsStore)
// This is emptied in snapshot postprocess!
exportedProofsStore = {
proofs: getSnapshot(proofsStore.proofs),
pendingProofs: getSnapshot(proofsStore.pendingProofs),
pendingByMintSecrets: getSnapshot(proofsStore.pendingByMintSecrets)
}
// log.trace({exportedProofsStore})
}
if(isMintsInBackup) {
+114 -67
View File
@@ -6,7 +6,7 @@ import { btoa, atob } from 'react-native-quick-base64'
import QuickCrypto from 'react-native-quick-crypto'
import { wordlist } from '@scure/bip39/wordlists/english'
import {colors, spacing, typography, useThemeColor} from '../theme'
import {AppStackScreenProps} from '../navigation' // @demo remove-current-line
import {AppStackScreenProps, goBack} from '../navigation' // @demo remove-current-line
import {
Icon,
ListItem,
@@ -17,30 +17,21 @@ import {
ErrorModal,
InfoModal,
BottomModal,
Button,
$sizeStyles,
Button,
} from '../components'
import {useHeader} from '../utils/useHeader'
import AppError, { Err } from '../utils/AppError'
import { KeyChain, log, MinibitsClient, NostrClient } from '../services'
import { Database, KeyChain, log, MinibitsClient, NostrClient } from '../services'
import Clipboard from '@react-native-clipboard/clipboard'
import { useStores } from '../models'
import { MintListItem } from './Mints/MintListItem'
import { rootStoreInstance, useStores } from '../models'
import {MnemonicInput} from './Recovery/MnemonicInput'
import { Mint } from '../models/Mint'
import { MintKeyset } from '@cashu/cashu-ts'
import { CashuUtils } from '../services/cashu/cashuUtils'
import { Proof } from '../models/Proof'
import { Transaction, TransactionData, TransactionRecord, TransactionStatus, TransactionType } from '../models/Transaction'
import { TransactionData, TransactionStatus } from '../models/Transaction'
import { ResultModalInfo } from './Wallet/ResultModalInfo'
import { deriveSeedFromMnemonic } from '@cashu/cashu-ts'
import { MINIBITS_NIP05_DOMAIN } from '@env'
import { MINIBITS_MINT_URL, MINIBITS_NIP05_DOMAIN } from '@env'
import { delay } from '../utils/utils'
import { getSnapshot, isStateTreeNode } from 'mobx-state-tree'
import { scale, verticalScale } from '@gocodingnow/rn-size-matters'
import { WalletUtils } from '../services/wallet/utils'
import { MintUnit, formatCurrency, getCurrency } from '../services/wallet/currency'
import { isObj } from '@cashu/cashu-ts/src/utils'
import { applySnapshot} from 'mobx-state-tree'
import { verticalScale } from '@gocodingnow/rn-size-matters'
import { WalletProfileRecord } from '../models/WalletProfileStore'
import { translate } from '../i18n'
import { ProofsStoreSnapshot } from '../models/ProofsStore'
@@ -66,7 +57,8 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
mintsStore,
proofsStore,
userSettingsStore,
transactionsStore,
transactionsStore,
contactsStore,
walletProfileStore,
walletStore
} = useStores()
@@ -82,7 +74,12 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
const [seed, setSeed] = useState<Uint8Array>()
const [backup, setBackup] = useState<string>('')
const [isValidBackup, setIsValidBackup] = useState(false)
const [walletSnapshot, setWalletSnapshot] = useState<any | undefined>(undefined) // type tbd
const [walletSnapshot, setWalletSnapshot] = useState<{
proofsStore: ProofsStoreSnapshot,
mintsStore: MintsStoreSnapshot,
contactsStore: ContactsStoreSnapshot,
transactionsStore: TransactionsStoreSnapshot
} | undefined>(undefined) // type tbd
const [profileToRecover, setProfileToRecover] = useState<WalletProfileRecord | undefined>(undefined)
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<AppError | undefined>()
@@ -115,17 +112,14 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
setIsResultModalVisible(previousState => !previousState)
}
// Used by both Wallet address and Import backup flows
const onConfirmMnemonic = async function () {
try {
setStatusMessage(translate("derivingSeedStatus"))
if(!mnemonic) {
throw new AppError(Err.VALIDATION_ERROR, translate('backupScreen.missingMnemonicError'))
}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(true)
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
if (!validateMnemonic(mnemonic, wordlist)) {
throw new AppError(Err.VALIDATION_ERROR, translate("recoveryInvalidMnemonicError"))
@@ -137,15 +131,13 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
console.log(`[onConfirm] deriveSeedFromMnemonic took ${end - start} ms.`)
setSeed(binarySeed)
setIsValidMnemonic(true)
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(false)
setIsValidMnemonic(true)
} catch (e: any) {
handleError(e)
}
}
// Used by Import backup flow
const onPasteBackup = async function () {
try {
const maybeBackup = await Clipboard.getString()
@@ -162,7 +154,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
}
}
// Used by Import backup flow
const getWalletSnapshot = function () {
try {
// decode
@@ -187,22 +179,19 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
}
}
// Used by Import backup flow
const onConfirmBackup = async function () {
try {
if(!backup) {
throw new AppError(Err.VALIDATION_ERROR, 'Missing backup.')
}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(true)
const snapshot = getWalletSnapshot() // throws
setWalletSnapshot(snapshot)
setIsValidBackup(true)
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(false)
await onFindWalletAddress()
} catch (e: any) {
handleError(e)
}
@@ -213,20 +202,16 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
return navigation.goBack()
}
const startImport = async function () {
setStatusMessage(translate("recovery.starting"))
setIsLoading(true)
// setTimeout(() => doRecovery(), 100)
}
// Used by both Wallet address and Import backup flows
const onFindWalletAddress = async () => {
try {
if(!seed || !mnemonic) {
throw new AppError(Err.VALIDATION_ERROR, translate("backupScreen.missingMnemonicOrSeedError"))
}
setStatusMessage(translate('recovery.recoveringAddress'))
setIsLoading(true)
const seedHash = QuickCrypto.createHash('sha256')
.update(seed)
.digest('hex')
@@ -244,14 +229,68 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
await delay(4000)
}
} else {
setInfo(translate("recovery.noWalletForSeedError"))
}
if(isAddressOnlyRecovery) {
setInfo(translate("recovery.noWalletForSeedError"))
}
}
setStatusMessage('')
setIsLoading(false)
} catch (e: any) {
handleError(e)
}
}
// Used by Import backup flow
const importWallet = async function () {
try {
if(!walletSnapshot) {
throw new AppError(Err.VALIDATION_ERROR, 'Missing wallet spnapshot decoded from backup.')
}
setStatusMessage(translate("recovery.starting"))
setIsLoading(true)
// import wallet snapshot into the state
const rootStore = rootStoreInstance
log.trace('Before import', {rootStore})
log.trace('Snapshot ot be imported', {walletSnapshot})
applySnapshot(proofsStore, walletSnapshot.proofsStore)
applySnapshot(mintsStore, walletSnapshot.mintsStore)
applySnapshot(contactsStore, walletSnapshot.contactsStore)
applySnapshot(transactionsStore, walletSnapshot.transactionsStore)
log.trace('After import', {rootStore})
// import proofs into the db
if(proofsStore.proofsCount > 0) {
Database.addOrUpdateProofs(proofsStore.allProofs, false, false)
}
if(proofsStore.pendingProofsCount > 0) {
Database.addOrUpdateProofs(proofsStore.allPendingProofs, true, false)
}
if(!mintsStore.mintExists(MINIBITS_MINT_URL)) {
await mintsStore.addMint(MINIBITS_MINT_URL)
}
if(profileToRecover) {
// If wallet profile has been found on server, recover wallet address
await onCompleteAddress()
} else {
// If there is no profile go back to the welcome screen to create a new one
goBack()
}
} catch (e: any) {
handleError(e)
}
}
// Used by both Wallet address and Import backup flows
const onCompleteAddress = async () => {
try {
if(!seed || !mnemonic || !profileToRecover) {
@@ -265,7 +304,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
.update(seed)
.digest('hex')
// get nostr key from current on device profile
// get nostr key from current on device profile (if we recover to existing wallet in Settings) or create new one (if we recover to new install)
const {publicKey: newPublicKey} = await NostrClient.getOrCreateKeyPair()
// delete orphaned server profile then update server profile with seedHash with pubkey + update on device wallet name and address
@@ -275,16 +314,19 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
userSettingsStore.setWalletId(walletProfileStore.walletId)
await KeyChain.saveMnemonic(mnemonic)
await KeyChain.saveSeed(seed as Uint8Array)
await delay(1000)
setStatusMessage(translate("recovery.completed"))
await delay(2000)
userSettingsStore.setIsOnboarded(true)
setStatusMessage(translate('recovery.completed'))
await delay(1000)
setStatusMessage('')
setIsLoading(false)
navigation.goBack()
if(isAddressOnlyRecovery) {
// go back to Settings
navigation.goBack()
} else {
navigation.navigate('Tabs', {screen: 'WalletNavigator', params: {screen: 'Wallet', params: {}}})
}
} catch (e: any) {
handleError(e)
}
@@ -301,7 +343,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
const inputBg = useThemeColor('background')
const headerTitle = useThemeColor('headerTitle')
if(false) {
if(mnemonicExists && !isAddressOnlyRecovery) {
return (
<Screen contentContainerStyle={$screen} preset="auto">
<View style={[$headerContainer, {backgroundColor: headerBg}]}>
@@ -340,7 +382,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
<Text
preset="heading"
text={isAddressOnlyRecovery ? "Recover address" : "Import backup"}
style={{color: headerTitle, zIndex: 10}}
style={{color: headerTitle, textAlign: 'center'}}
/>
</View>
<View style={$contentContainer}>
@@ -369,7 +411,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
ref={backupInputRef}
onChangeText={(backup: string) => setBackup(backup)}
value={backup}
numberOfLines={5}
numberOfLines={3}
multiline={true}
autoCapitalize='none'
keyboardType='default'
@@ -401,7 +443,7 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
ContentComponent={
<ListItem
text='Wallet backup'
subText={`${backup.slice(0, 100)}...`}
subText={`${backup.slice(0, 50)}...`}
subTextStyle={{fontFamily: typography.code?.normal}}
LeftComponent={<View style={[$numIcon, {backgroundColor: numIconColor}]}><Text text='2'/></View>}
style={$item}
@@ -409,14 +451,14 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
}
/>
)}
{isValidMnemonic && profileToRecover && isAddressOnlyRecovery && (
{isValidMnemonic && profileToRecover && (
<Card
style={$card}
ContentComponent={
<ListItem
text={profileToRecover.nip05}
subTx="profileToRecoverDesc"
LeftComponent={<View style={[$numIcon, {backgroundColor: numIconColor}]}><Text text='2'/></View>}
LeftComponent={<View style={[$numIcon, {backgroundColor: numIconColor}]}><Text text={isAddressOnlyRecovery ? '2' : '3'}/></View>}
style={$item}
/>
}
@@ -455,16 +497,21 @@ export const ImportBackupScreen: FC<AppStackScreenProps<'ImportBackup'>> = obser
)}
</>
) : (
<Button
text={`Import wallet`}
LeftAccessory={() => (
<Icon
icon='faDownload'
size={spacing.medium}
<>
{isValidBackup && (
<Button
text={`Import wallet`}
LeftAccessory={() => (
<Icon
icon='faDownload'
size={spacing.medium}
/>
)}
onPress={importWallet}
/>
)}
onPress={startImport}
/>
</>
)}
</View>
+2 -2
View File
@@ -160,7 +160,7 @@ export const RecoveryOptionsScreen: FC<AppStackScreenProps<'RecoveryOptions'>> =
tx="recoveryOptions.fromSeed"
subTx="recoveryOptions.fromSeedDescription"
leftIcon='faSeedling'
leftIconColor={colors.palette.blue200}
leftIconColor={colors.palette.orange400}
leftIconInverse={true}
style={$item}
onPress={gotoSeedRecovery}
@@ -178,7 +178,7 @@ export const RecoveryOptionsScreen: FC<AppStackScreenProps<'RecoveryOptions'>> =
tx="walletAddressRecovery"
subTx="walletAddressRecoveryDesc"
leftIcon='faCircleUser'
leftIconColor={colors.palette.iconGreyBlue400}
leftIconColor={colors.palette.iconViolet300}
leftIconInverse={true}
style={$item}
onPress={gotoAddressRecovery}
+28 -30
View File
@@ -32,7 +32,7 @@ import { Proof } from '../models/Proof'
import { Transaction, TransactionData, TransactionRecord, TransactionStatus, TransactionType } from '../models/Transaction'
import { ResultModalInfo } from './Wallet/ResultModalInfo'
import { deriveSeedFromMnemonic } from '@cashu/cashu-ts'
import { MINIBITS_NIP05_DOMAIN } from '@env'
import { MINIBITS_MINT_URL, MINIBITS_NIP05_DOMAIN } from '@env'
import { delay } from '../utils/utils'
import { getSnapshot, isStateTreeNode } from 'mobx-state-tree'
import { scale } from '@gocodingnow/rn-size-matters'
@@ -143,31 +143,23 @@ export const SeedRecoveryScreen: FC<AppStackScreenProps<'SeedRecovery'>> = obser
const onConfirm = async function () {
try {
setStatusMessage(translate("derivingSeedStatus"))
if(!mnemonic) {
throw new AppError(Err.VALIDATION_ERROR, translate('backupScreen.missingMnemonicError'))
}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(true)
}
if (!validateMnemonic(mnemonic, wordlist)) {
throw new AppError(Err.VALIDATION_ERROR, translate("recoveryInvalidMnemonicError"))
}
}
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setTimeout(() => {
const start = performance.now()
const binarySeed = deriveSeedFromMnemonic(mnemonic) // expensive
const end = performance.now()
console.log(`[onConfirm] deriveSeedFromMnemonic took ${end - start} ms.`)
setSeed(binarySeed)
setIsValidMnemonic(true)
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setIsLoading(false)
}, 200)
const start = performance.now()
const binarySeed = deriveSeedFromMnemonic(mnemonic)
const end = performance.now()
console.log(`[onConfirm] deriveSeedFromMnemonic took ${end - start} ms.`)
setSeed(binarySeed)
setIsValidMnemonic(true)
} catch (e: any) {
handleError(e)
}
@@ -487,12 +479,10 @@ export const SeedRecoveryScreen: FC<AppStackScreenProps<'SeedRecovery'>> = obser
setStatusMessage(translate('recovery.recoveringAddress'))
setIsLoading(true)
await KeyChain.saveMnemonic(mnemonic)
await KeyChain.saveSeed(seed as Uint8Array)
// Wallet address recovery
const seedHash = await KeyChain.loadSeedHash()
const seedHash = QuickCrypto.createHash('sha256')
.update(seed)
.digest('hex')
log.trace('[onComplete]', 'getWalletProfileBySeedHash')
const profileToRecover = await MinibitsClient.getWalletProfileBySeedHash(seedHash as string)
@@ -508,19 +498,27 @@ export const SeedRecoveryScreen: FC<AppStackScreenProps<'SeedRecovery'>> = obser
await walletProfileStore.recover(seedHash as string, newPublicKey)
// Align walletId in userSettings with recovered profile
userSettingsStore.setWalletId(walletProfileStore.walletId)
await delay(1000)
setStatusMessage(translate('recovery.completed'))
await delay(2000)
} else {
setInfo(translate("recovery.ownKeysImportAgain", { addr: profileToRecover.nip05 }))
await delay(5000)
await delay(4000)
}
}
userSettingsStore.setIsOnboarded(true)
await KeyChain.saveMnemonic(mnemonic)
await KeyChain.saveSeed(seed as Uint8Array)
if(!mintsStore.mintExists(MINIBITS_MINT_URL)) {
await mintsStore.addMint(MINIBITS_MINT_URL)
}
setStatusMessage(translate('recovery.completed'))
await delay(2000)
setStatusMessage('')
setIsLoading(false)
navigation.navigate('Tabs')
navigation.navigate('Tabs', {screen: 'WalletNavigator', params: {screen: 'Wallet', params: {}}})
} catch (e: any) {
handleError(e)
}
+12 -5
View File
@@ -96,6 +96,7 @@ export const WelcomeScreen: FC<AppStackScreenProps<'Welcome'>> =
const [error, setError] = useState<AppError | undefined>()
const [isLoading, setIsLoading] = useState<boolean>(false)
const [statusMessage, setStatusMessage] = useState<string>('')
const [info, setInfo] = useState<string>('')
const gotoWallet = async function () {
@@ -107,10 +108,13 @@ export const WelcomeScreen: FC<AppStackScreenProps<'Welcome'>> =
// do not overwrite if one was set during recovery
setIsLoading(true)
const mnemonic = await walletStore.getOrCreateMnemonic()
setStatusMessage('Setting wallet seed...')
await walletStore.getOrCreateMnemonic()
// move new profile creation to the app start so that device token can register
if(!walletProfileStore.pubkey || !walletProfileStore.picture) {
if(!walletProfileStore.pubkey || !walletProfileStore.picture) {
setStatusMessage('Creating wallet profile...')
const walletId = userSettingsStore.walletId
await walletProfileStore.create(walletId as string)
}
@@ -121,9 +125,12 @@ export const WelcomeScreen: FC<AppStackScreenProps<'Welcome'>> =
relaysStore.addDefaultRelays()
userSettingsStore.setIsOnboarded(true)
navigation.navigate('Tabs')
userSettingsStore.setIsOnboarded(true)
setStatusMessage('')
setIsLoading(false)
navigation.navigate('Tabs', {screen: 'WalletNavigator', params: {screen: 'Wallet', params: {}}})
} catch (e: any) {
handleError(e)
}
@@ -269,7 +276,7 @@ export const WelcomeScreen: FC<AppStackScreenProps<'Welcome'>> =
</View>
{error && <ErrorModal error={error} />}
{info && <InfoModal message={info} />}
{isLoading && <Loading statusMessage={translate("welcomeScreen.generatingWalletSeedStatusMessage")} style={{backgroundColor: headerBg, opacity: 1}} textStyle={{color: 'white'}}/>}
{isLoading && <Loading statusMessage={statusMessage} style={{backgroundColor: headerBg, opacity: 1}} textStyle={{color: 'white'}}/>}
</Screen>
)
}
+1
View File
@@ -241,6 +241,7 @@ const clearAll = function (): void {
try {
const storage = getInstance()
storage.clearAll()
log.trace('[clearAll] Wallet state cleared.')
} catch (e: any) {
throw new AppError(Err.DATABASE_ERROR, e.message)
}
+6 -5
View File
@@ -122,7 +122,7 @@ const _createOrUpdateSchema = function (db: QuickSQLiteConnection) {
log.info('[_createOrUpdateSchema] New database schema created')
}
const {version} = getDatabaseVersion()
const {version} = getDatabaseVersion(db)
log.info('[_createOrUpdateSchema]', `Device database version: ${version}`)
// Trigger migrations if there is versions mismatch
@@ -143,7 +143,7 @@ const _createOrUpdateSchema = function (db: QuickSQLiteConnection) {
const _runMigrations = function (db: QuickSQLiteConnection) {
const now = new Date()
const {version} = getDatabaseVersion()
const {version} = getDatabaseVersion(db)
let currentVersion = version
let migrationQueries: SQLBatchTuple[] = []
@@ -383,12 +383,12 @@ const cleanAll = function () {
}
const getDatabaseVersion = function (): {version: number} {
const getDatabaseVersion = function (db: QuickSQLiteConnection): {version: number} {
try {
const query = `
SELECT version FROM dbVersion
`
const db = getInstance()
const {rows} = db.execute(query)
if (!rows?.item(0)) {
@@ -1166,7 +1166,8 @@ const addOrUpdateProofs = function (
const db = getInstance()
const {rowsAffected} = db.executeBatch(insertQueries)
const totalAmount = CashuUtils.getProofsAmount(proofs)
// const totalAmount = CashuUtils.getProofsAmount(proofs)
// DO NOT log proof secrets to Sentry
log.info('[addOrUpdateProofs]',
`${rowsAffected}${isPending ? ' pending' : ''