Skip to content

Commit

Permalink
add screen component for keyset selection
Browse files Browse the repository at this point in the history
  • Loading branch information
KKA11010 committed Apr 1, 2024
1 parent f7b975f commit df008b5
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 218 deletions.
157 changes: 0 additions & 157 deletions src/components/hooks/Restore.tsx

This file was deleted.

6 changes: 4 additions & 2 deletions src/components/nav/Navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ import RecoverScreen from '@screens/Restore/Recover'
import RecoveringScreen from '@screens/Restore/Recovering'
import RestoreWarningScreen from '@screens/Restore/RestoreWarning'
import SeedScreen from '@screens/Restore/Seed'
import SelectKeysetScreen from '@screens/Restore/SelectKeyset'
import SelectRecoveryMintScreen from '@screens/Restore/SelectRecoveryMint'
import RestoreSuccess from '@screens/Restore/Success'
import RestoreOverviewScreen from '@screens/Restore/Success'
import Settings from '@screens/Settings'
import AboutSettings from '@screens/Settings/About'
import ContactsSettings from '@screens/Settings/Contacts'
Expand Down Expand Up @@ -198,7 +199,8 @@ export default function Navigator({
<Stack.Screen name='Recovering' component={RecoveringScreen} />
<Stack.Screen name='Select recovery mint' component={SelectRecoveryMintScreen} />
<Stack.Screen name='Restore warning' component={RestoreWarningScreen} />
<Stack.Screen name='restoreSuccess' component={RestoreSuccess} />
<Stack.Screen name='restoreOverview' component={RestoreOverviewScreen} />
<Stack.Screen name='selectKeyset' component={SelectKeysetScreen} />
</Stack.Navigator>
</View>
)
Expand Down
10 changes: 8 additions & 2 deletions src/model/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export type RootStackParamList = {
'Restore warning': {
comingFromOnboarding?: boolean
}
restoreSuccess: {
restoreOverview: {
mnemonic: string
amount: number
mint: string
Expand All @@ -257,6 +257,11 @@ export type RootStackParamList = {
}
comingFromOnboarding?: boolean
}
selectKeyset: {
mnemonic: string
mintUrl: string
comingFromOnboarding?: boolean
}
}

export type TRouteString = 'dashboard' | 'mints' | 'Address book' | 'Settings'
Expand Down Expand Up @@ -308,7 +313,8 @@ export type IDerivingPageProps = NativeStackScreenProps<RootStackParamList, 'Der
export type IRecoveringPageProps = NativeStackScreenProps<RootStackParamList, 'Recovering'>
export type ISelectRecoveryMintPageProps = NativeStackScreenProps<RootStackParamList, 'Select recovery mint'>
export type IRestoreWarningPageProps = NativeStackScreenProps<RootStackParamList, 'Restore warning'>
export type IRestoreSuccessPageProps = NativeStackScreenProps<RootStackParamList, 'restoreSuccess'>
export type IRestoreSuccessPageProps = NativeStackScreenProps<RootStackParamList, 'restoreOverview'>
export type ISelectKeysetPageProps = NativeStackScreenProps<RootStackParamList, 'selectKeyset'>
export type TBottomNavProps =
TNostrOnboardingPageProps |
TDashboardPageProps |
Expand Down
137 changes: 123 additions & 14 deletions src/screens/Restore/Recovering.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,138 @@
import { useRestore } from '@comps/hooks/Restore'
import type { CashuWallet, MintKeys, Proof } from '@cashu/cashu-ts'
import Loading from '@comps/Loading'
import Txt from '@comps/Txt'
import { RESTORE_INTERVAL, RESTORE_OVERSHOOT } from '@consts/mints'
import { addToken, getMintBalance } from '@db'
import { l } from '@log'
import type { IRecoveringPageProps, TBeforeRemoveEvent } from '@model/nav'
import { preventBack } from '@nav/utils'
import { RESTORE_OVERSHOOT } from '@src/consts/mints'
import { useThemeContext } from '@src/context/Theme'
import { NS } from '@src/i18n'
import { formatSatStr } from '@src/util'
import { saveSeed } from '@store/restore'
import { globals, mainColors } from '@styles'
import { useEffect } from 'react'
import { formatSatStr, isErr } from '@util'
import { _setKeys, getCounterByMintUrl, getSeedWalletByMnemonic, incrementCounterByMintUrl } from '@wallet'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { s, ScaledSheet } from 'react-native-size-matters'

type TRestoreInterval = Promise<{ proofs: Proof[]; newKeys?: MintKeys; start: number; lastCount: number } | undefined>

export default function RecoveringScreen({ navigation, route }: IRecoveringPageProps) {

const { from, to, mintUrl, keysetId, mnemonic, comingFromOnboarding, shouldOvershoot } = route.params

const { t } = useTranslation([NS.common])
// Seed recovery process in useRestore hook
const { proofs, start, end, overshoot } = useRestore({ from, to, mintUrl, keysetId, mnemonic, comingFromOnboarding, shouldOvershoot })

const { color } = useThemeContext()

const [restored, setRestored] = useState({
proofs: [] as Proof[],
start: from,
end: to,
overshoot: 0,
})

const resetRestoredState = () => {
setRestored({
proofs: [] as Proof[],
start: from,
end: to,
overshoot: 0,
})
}

const restore = async () => {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const { start, end } = await restoreWallet(mintUrl, mnemonic)
const bal = await getMintBalance(mintUrl)
// TODO save keysetID as restored: [{ keysetId, amount: bal }, ...]
navigation.navigate('restoreOverview', {
mnemonic,
mint: mintUrl,
keysetID: keysetId,
cycle: { start, end },
amount: bal,
comingFromOnboarding,
})
} catch (e) {
l('[handleRecovery] error: ', e)
resetRestoredState()
navigation.navigate('processingError', {
errorMsg: isErr(e) ? e.message : t('restoreErr'),
comingFromOnboarding,
})
}
}

const restoreWallet = async (mintUrl: string, mnemonic: string) => {
try {
const { wallet, seed } = await getSeedWalletByMnemonic({ mintUrl, mnemonic })
const resp = await restoreInterval(wallet, from, to)
if (!resp) {
l('[restoreWallet] restore interval did not return a proper object!')
throw new Error('[restoreWallet] restore interval did not return a proper object!')
}
const { proofs, newKeys, start, lastCount } = resp
await saveSeed(seed)
// adds counter if not exists
await getCounterByMintUrl(mintUrl)
if (!proofs.length) {
l('[restoreWallet] no proofs found during the restore process!')
return { start: from, end: to }
}
const proofsSpent = await wallet.checkProofsSpent(proofs)
const proofsUnspent = proofs.filter(p => !proofsSpent.map(x => x.secret).includes(p.secret))
if (newKeys) { _setKeys(mintUrl, newKeys) }
await addToken({ token: [{ mint: mintUrl, proofs: proofsUnspent }] })
await incrementCounterByMintUrl(mintUrl, lastCount + 1)
return { start, end: lastCount }
} catch (e) {
l('[restoreWallet] error', { e })
return { start: from, end: to }
}
}

const restoreInterval = async (
wallet: CashuWallet,
start: number,
end: number,
restoredProofs: Proof[] = [],
overshoot: number = 0
): TRestoreInterval => {
try {
const { proofs, newKeys } = await wallet.restore(start, end, keysetId)
l('[restoreInterval] restored proofs: ', { from: start, to: end, proofsLength: proofs.length })
if (proofs.length) {
restoredProofs.push(...proofs)
overshoot = 0
start += RESTORE_INTERVAL
end += RESTORE_INTERVAL
setRestored({ proofs: restoredProofs, start, end, overshoot })
return restoreInterval(wallet, start, end, restoredProofs, overshoot)
}
if (shouldOvershoot && overshoot < RESTORE_OVERSHOOT) {
l('[restoreInterval] no proofs to restore! overshooting now: ', { proofsLength: proofs.length, overshoot })
overshoot++
start += RESTORE_INTERVAL
end += RESTORE_INTERVAL
setRestored({ proofs: restoredProofs, start, end, overshoot })
return restoreInterval(wallet, start, end, restoredProofs, overshoot)
}
l('[restoreInterval] no proofs to restore! overshooting limit reached: ', { restoredProofsLength: restoredProofs.length, overshoot })
return { proofs: restoredProofs, newKeys, start, lastCount: end }
} catch (e) {
l('[restoreInterval] error', { e })
return { proofs: restoredProofs, newKeys: undefined, start, lastCount: end }
}
}

useEffect(() => {
resetRestoredState()
void restore()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mintUrl, keysetId, from, to])

// prevent back navigation - https://reactnavigation.org/docs/preventing-going-back/
useEffect(() => {
const backHandler = (e: TBeforeRemoveEvent) => preventBack(e, navigation.dispatch)
Expand All @@ -39,10 +149,10 @@ export default function RecoveringScreen({ navigation, route }: IRecoveringPageP
/>
<Txt
center
bold={overshoot > 0}
styles={[styles.hint, { color: overshoot > 0 ? mainColors.VALID : mainColors.WARN, marginBottom: s(40) }]}
bold={restored.overshoot > 0}
styles={[styles.hint, { color: restored.overshoot > 0 ? mainColors.VALID : mainColors.WARN, marginBottom: s(40) }]}
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
txt={overshoot > 0 ? `${t('doneSafety')} ${overshoot}/${RESTORE_OVERSHOOT}` : t('dontClose')}
txt={restored.overshoot > 0 ? `${t('doneSafety')} ${restored.overshoot}/${RESTORE_OVERSHOOT}` : t('dontClose')}
/>
<View style={styles.progress}>
<Txt
Expand All @@ -63,7 +173,7 @@ export default function RecoveringScreen({ navigation, route }: IRecoveringPageP
/>
<Txt
styles={[styles.hint, { color: color.TEXT_SECONDARY }]}
txt={`${start} ${t('to')} ${end}`}
txt={`${restored.start} ${t('to')} ${restored.end}`}
/>
</View>
<View style={styles.progress}>
Expand All @@ -74,10 +184,9 @@ export default function RecoveringScreen({ navigation, route }: IRecoveringPageP
/>
<Txt
styles={[styles.hint, { color: color.TEXT_SECONDARY }]}
txt={`${proofs.length} ${t('proofs', { ns: NS.wallet })} (${formatSatStr(proofs.reduce((acc, p) => acc + p.amount, 0))})`}
txt={`${restored.proofs.length} ${t('proofs', { ns: NS.wallet })} (${formatSatStr(restored.proofs.reduce((acc, p) => acc + p.amount, 0))})`}
/>
</View>

</View>
)
}
Expand Down
Loading

0 comments on commit df008b5

Please sign in to comment.