mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
Merge pull request #7293 from BlueWallet/import-offline
feat: offline import
This commit is contained in:
commit
219130a5e8
@ -1113,7 +1113,7 @@ export const testConnection = async function (host: string, tcpPort?: number, ss
|
||||
};
|
||||
|
||||
export const forceDisconnect = (): void => {
|
||||
mainClient.close();
|
||||
mainClient?.close();
|
||||
};
|
||||
|
||||
export const setBatchingDisabled = () => {
|
||||
|
@ -53,6 +53,7 @@ const startImport = (
|
||||
importTextOrig: string,
|
||||
askPassphrase: boolean = false,
|
||||
searchAccounts: boolean = false,
|
||||
offline: boolean = false,
|
||||
onProgress: (name: string) => void,
|
||||
onWallet: (wallet: TWallet) => void,
|
||||
onPassword: (title: string, text: string) => Promise<string>,
|
||||
@ -67,6 +68,18 @@ const startImport = (
|
||||
promiseReject = reject;
|
||||
});
|
||||
|
||||
// helpers
|
||||
// in offline mode all wallets are considered used
|
||||
const wasUsed = async (wallet: TWallet): Promise<boolean> => {
|
||||
if (offline) return true;
|
||||
return wallet.wasEverUsed();
|
||||
};
|
||||
const fetch = async (wallet: TWallet, balance: boolean = false, transactions: boolean = false) => {
|
||||
if (offline) return;
|
||||
if (balance) await wallet.fetchBalance();
|
||||
if (transactions) await wallet.fetchTransactions();
|
||||
};
|
||||
|
||||
// actions
|
||||
const reportProgress = (name: string) => {
|
||||
onProgress(name);
|
||||
@ -165,7 +178,7 @@ const startImport = (
|
||||
const ms = new MultisigHDWallet();
|
||||
ms.setSecret(text);
|
||||
if (ms.getN() > 0 && ms.getM() > 0) {
|
||||
await ms.fetchBalance();
|
||||
await fetch(ms, true, false);
|
||||
yield { wallet: ms };
|
||||
}
|
||||
|
||||
@ -179,11 +192,13 @@ const startImport = (
|
||||
lnd.setSecret(split[0]);
|
||||
}
|
||||
await lnd.init();
|
||||
await lnd.authorize();
|
||||
await lnd.fetchTransactions();
|
||||
await lnd.fetchUserInvoices();
|
||||
await lnd.fetchPendingTransactions();
|
||||
await lnd.fetchBalance();
|
||||
if (!offline) {
|
||||
await lnd.authorize();
|
||||
await lnd.fetchTransactions();
|
||||
await lnd.fetchUserInvoices();
|
||||
await lnd.fetchPendingTransactions();
|
||||
await lnd.fetchBalance();
|
||||
}
|
||||
yield { wallet: lnd };
|
||||
}
|
||||
|
||||
@ -228,7 +243,7 @@ const startImport = (
|
||||
}
|
||||
wallet.setDerivationPath(path);
|
||||
yield { progress: `bip39 ${i.script_type} ${path}` };
|
||||
if (await wallet.wasEverUsed()) {
|
||||
if (await wasUsed(wallet)) {
|
||||
yield { wallet };
|
||||
walletFound = true;
|
||||
} else {
|
||||
@ -247,11 +262,12 @@ const startImport = (
|
||||
m0Legacy.setDerivationPath("m/0'");
|
||||
yield { progress: "bip39 p2pkh m/0'" };
|
||||
// BRD doesn't support passphrase and only works with 12 words seeds
|
||||
if (!password && text.split(' ').length === 12) {
|
||||
// do not try to guess BRD wallet in offline mode
|
||||
if (!password && text.split(' ').length === 12 && !offline) {
|
||||
const brd = new HDLegacyBreadwalletWallet();
|
||||
brd.setSecret(text);
|
||||
|
||||
if (await m0Legacy.wasEverUsed()) {
|
||||
if (await wasUsed(m0Legacy)) {
|
||||
await m0Legacy.fetchBalance();
|
||||
await m0Legacy.fetchTransactions();
|
||||
yield { progress: 'BRD' };
|
||||
@ -265,7 +281,7 @@ const startImport = (
|
||||
walletFound = true;
|
||||
}
|
||||
} else {
|
||||
if (await m0Legacy.wasEverUsed()) {
|
||||
if (await wasUsed(m0Legacy)) {
|
||||
yield { wallet: m0Legacy };
|
||||
walletFound = true;
|
||||
}
|
||||
@ -275,7 +291,6 @@ const startImport = (
|
||||
if (!walletFound) {
|
||||
yield { wallet: hd2 };
|
||||
}
|
||||
// return;
|
||||
}
|
||||
|
||||
yield { progress: 'wif' };
|
||||
@ -288,17 +303,17 @@ const startImport = (
|
||||
yield { progress: 'wif p2wpkh' };
|
||||
const segwitBech32Wallet = new SegwitBech32Wallet();
|
||||
segwitBech32Wallet.setSecret(text);
|
||||
if (await segwitBech32Wallet.wasEverUsed()) {
|
||||
if (await wasUsed(segwitBech32Wallet)) {
|
||||
// yep, its single-address bech32 wallet
|
||||
await segwitBech32Wallet.fetchBalance();
|
||||
await fetch(segwitBech32Wallet, true);
|
||||
walletFound = true;
|
||||
yield { wallet: segwitBech32Wallet };
|
||||
}
|
||||
|
||||
yield { progress: 'wif p2wpkh-p2sh' };
|
||||
if (await segwitWallet.wasEverUsed()) {
|
||||
if (await wasUsed(segwitWallet)) {
|
||||
// yep, its single-address p2wpkh wallet
|
||||
await segwitWallet.fetchBalance();
|
||||
await fetch(segwitWallet, true);
|
||||
walletFound = true;
|
||||
yield { wallet: segwitWallet };
|
||||
}
|
||||
@ -307,9 +322,9 @@ const startImport = (
|
||||
yield { progress: 'wif p2pkh' };
|
||||
const legacyWallet = new LegacyWallet();
|
||||
legacyWallet.setSecret(text);
|
||||
if (await legacyWallet.wasEverUsed()) {
|
||||
if (await wasUsed(legacyWallet)) {
|
||||
// yep, its single-address legacy wallet
|
||||
await legacyWallet.fetchBalance();
|
||||
await fetch(legacyWallet, true);
|
||||
walletFound = true;
|
||||
yield { wallet: legacyWallet };
|
||||
}
|
||||
@ -327,8 +342,7 @@ const startImport = (
|
||||
const legacyWallet = new LegacyWallet();
|
||||
legacyWallet.setSecret(text);
|
||||
if (legacyWallet.getAddress()) {
|
||||
await legacyWallet.fetchBalance();
|
||||
await legacyWallet.fetchTransactions();
|
||||
await fetch(legacyWallet, true, true);
|
||||
yield { wallet: legacyWallet };
|
||||
}
|
||||
|
||||
@ -337,7 +351,7 @@ const startImport = (
|
||||
const watchOnly = new WatchOnlyWallet();
|
||||
watchOnly.setSecret(text);
|
||||
if (watchOnly.valid()) {
|
||||
await watchOnly.fetchBalance();
|
||||
await fetch(watchOnly, true);
|
||||
yield { wallet: watchOnly };
|
||||
}
|
||||
|
||||
@ -384,7 +398,7 @@ const startImport = (
|
||||
if (password) {
|
||||
s1.setPassphrase(password);
|
||||
}
|
||||
if (await s1.wasEverUsed()) {
|
||||
if (await wasUsed(s1)) {
|
||||
yield { wallet: s1 };
|
||||
}
|
||||
|
||||
@ -394,7 +408,7 @@ const startImport = (
|
||||
s2.setPassphrase(password);
|
||||
}
|
||||
s2.setSecret(text);
|
||||
if (await s2.wasEverUsed()) {
|
||||
if (await wasUsed(s2)) {
|
||||
yield { wallet: s2 };
|
||||
}
|
||||
|
||||
@ -433,6 +447,7 @@ const startImport = (
|
||||
if (next.value?.progress) reportProgress(next.value.progress);
|
||||
if (next.value?.wallet) reportWallet(next.value.wallet);
|
||||
if (next.done) break; // break if generator has been finished
|
||||
await new Promise(resolve => setTimeout(resolve, 1)); // try not to block the thread
|
||||
}
|
||||
reportFinish();
|
||||
})().catch(e => {
|
||||
|
@ -448,6 +448,7 @@
|
||||
"import_discovery_subtitle": "Choose a discovered wallet",
|
||||
"import_discovery_derivation": "Use custom derivation path",
|
||||
"import_discovery_no_wallets": "No wallets were found.",
|
||||
"import_discovery_offline": "BlueWallet is currently in offline mode. In this mode, it can't verify the existence of the wallet, so you'll need to select the correct one manually",
|
||||
"import_derivation_found": "Found",
|
||||
"import_derivation_found_not": "Not found",
|
||||
"import_derivation_loading": "Loading...",
|
||||
|
@ -20,7 +20,11 @@ import {
|
||||
|
||||
export type AddWalletStackParamList = {
|
||||
AddWallet: undefined;
|
||||
ImportWallet: undefined;
|
||||
ImportWallet?: {
|
||||
label?: string;
|
||||
triggerImport?: boolean;
|
||||
scannedData?: string;
|
||||
};
|
||||
ImportWalletDiscovery: {
|
||||
importText: string;
|
||||
askPassphrase: boolean;
|
||||
|
@ -7,7 +7,7 @@ const WalletsAdd = lazy(() => import('../screen/wallets/Add'));
|
||||
const ImportCustomDerivationPath = lazy(() => import('../screen/wallets/ImportCustomDerivationPath'));
|
||||
const ImportWalletDiscovery = lazy(() => import('../screen/wallets/ImportWalletDiscovery'));
|
||||
const ImportSpeed = lazy(() => import('../screen/wallets/ImportSpeed'));
|
||||
const ImportWallet = lazy(() => import('../screen/wallets/import'));
|
||||
const ImportWallet = lazy(() => import('../screen/wallets/ImportWallet'));
|
||||
const PleaseBackup = lazy(() => import('../screen/wallets/PleaseBackup'));
|
||||
const PleaseBackupLNDHub = lazy(() => import('../screen/wallets/pleaseBackupLNDHub'));
|
||||
const ProvideEntropy = lazy(() => import('../screen/wallets/ProvideEntropy'));
|
||||
|
@ -14,6 +14,7 @@ import WalletToImport from '../../components/WalletToImport';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import loc from '../../loc';
|
||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportCustomDerivationPath'>;
|
||||
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'ImportCustomDerivationPath'>;
|
||||
@ -44,6 +45,7 @@ const ImportCustomDerivationPath: React.FC = () => {
|
||||
const [used, setUsed] = useState<TUsedByPath>({});
|
||||
const [selected, setSelected] = useState<string>('');
|
||||
const importing = useRef(false);
|
||||
const { isElectrumDisabled } = useSettings();
|
||||
|
||||
const debouncedSavePath = useRef(
|
||||
debounce(async newPath => {
|
||||
@ -65,6 +67,14 @@ const ImportCustomDerivationPath: React.FC = () => {
|
||||
}
|
||||
setWallets(ws => ({ ...ws, [newPath]: newWallets }));
|
||||
|
||||
if (isElectrumDisabled) {
|
||||
// do not check if electrum is disabled
|
||||
Object.values(newWallets).forEach(w => {
|
||||
setUsed(u => ({ ...u, [newPath]: { ...u[newPath], [w.type]: STATUS.WALLET_UNKNOWN } }));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// discover was they ever used
|
||||
const promises = Object.values(newWallets).map(w => {
|
||||
return w.wasEverUsed().then(v => {
|
||||
@ -81,6 +91,7 @@ const ImportCustomDerivationPath: React.FC = () => {
|
||||
}
|
||||
}, 500),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (path in wallets) return;
|
||||
debouncedSavePath.current(path);
|
||||
|
@ -1,36 +1,41 @@
|
||||
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { useRoute } from '@react-navigation/native';
|
||||
import { Keyboard, Platform, StyleSheet, TouchableWithoutFeedback, View, ScrollView } from 'react-native';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { RouteProp, useRoute } from '@react-navigation/native';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { Keyboard, Platform, ScrollView, StyleSheet, TouchableWithoutFeedback, View } from 'react-native';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { BlueButtonLink, BlueFormLabel, BlueFormMultiInput, BlueSpacing20 } from '../../BlueComponents';
|
||||
import Button from '../../components/Button';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { scanQrHelper } from '../../helpers/scan-qr';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import loc from '../../loc';
|
||||
import {
|
||||
DoneAndDismissKeyboardInputAccessory,
|
||||
DoneAndDismissKeyboardInputAccessoryViewID,
|
||||
} from '../../components/DoneAndDismissKeyboardInputAccessory';
|
||||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { useKeyboard } from '../../hooks/useKeyboard';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import HeaderMenuButton from '../../components/HeaderMenuButton';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { scanQrHelper } from '../../helpers/scan-qr';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import { useKeyboard } from '../../hooks/useKeyboard';
|
||||
import loc from '../../loc';
|
||||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
|
||||
const WalletsImport = () => {
|
||||
const navigation = useExtendedNavigation();
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
type NavigationProps = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
|
||||
const ImportWallet = () => {
|
||||
const navigation = useExtendedNavigation<NavigationProps>();
|
||||
const { colors } = useTheme();
|
||||
const route = useRoute();
|
||||
const route = useRoute<RouteProps>();
|
||||
const label = route?.params?.label ?? '';
|
||||
const triggerImport = route?.params?.triggerImport ?? false;
|
||||
const scannedData = route?.params?.scannedData ?? '';
|
||||
const [importText, setImportText] = useState(label);
|
||||
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
|
||||
const [, setSpeedBackdoor] = useState(0);
|
||||
const [searchAccountsMenuState, setSearchAccountsMenuState] = useState(false);
|
||||
const [askPassphraseMenuState, setAskPassphraseMenuState] = useState(false);
|
||||
const [clearClipboardMenuState, setClearClipboardMenuState] = useState(true);
|
||||
const [importText, setImportText] = useState<string>(label);
|
||||
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState<boolean>(false);
|
||||
const [, setSpeedBackdoor] = useState<number>(0);
|
||||
const [searchAccountsMenuState, setSearchAccountsMenuState] = useState<boolean>(false);
|
||||
const [askPassphraseMenuState, setAskPassphraseMenuState] = useState<boolean>(false);
|
||||
const [clearClipboardMenuState, setClearClipboardMenuState] = useState<boolean>(true);
|
||||
const { isPrivacyBlurEnabled } = useSettings();
|
||||
// Styles
|
||||
const styles = StyleSheet.create({
|
||||
@ -46,11 +51,11 @@ const WalletsImport = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const onBlur = () => {
|
||||
const onBlur = useCallback(() => {
|
||||
const valueWithSingleWhitespace = importText.replace(/^\s+|\s+$|\s+(?=\s)/g, '');
|
||||
setImportText(valueWithSingleWhitespace);
|
||||
return valueWithSingleWhitespace;
|
||||
};
|
||||
}, [importText]);
|
||||
|
||||
useKeyboard({
|
||||
onKeyboardDidShow: () => {
|
||||
@ -61,62 +66,50 @@ const WalletsImport = () => {
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
disallowScreenshot(isPrivacyBlurEnabled);
|
||||
return () => {
|
||||
disallowScreenshot(false);
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
const importMnemonic = useCallback(
|
||||
async (text: string) => {
|
||||
if (clearClipboardMenuState) {
|
||||
try {
|
||||
if (await Clipboard.hasString()) {
|
||||
Clipboard.setString('');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to clear clipboard:', error);
|
||||
}
|
||||
}
|
||||
navigation.navigate('ImportWalletDiscovery', {
|
||||
importText: text,
|
||||
askPassphrase: askPassphraseMenuState,
|
||||
searchAccounts: searchAccountsMenuState,
|
||||
});
|
||||
},
|
||||
[askPassphraseMenuState, clearClipboardMenuState, navigation, searchAccountsMenuState],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerImport) importButtonPressed();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [triggerImport]);
|
||||
|
||||
useEffect(() => {
|
||||
if (scannedData) {
|
||||
onBarScanned(scannedData);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [scannedData]);
|
||||
|
||||
const importButtonPressed = () => {
|
||||
const handleImport = useCallback(() => {
|
||||
const textToImport = onBlur();
|
||||
if (textToImport.trim().length === 0) {
|
||||
return;
|
||||
}
|
||||
importMnemonic(textToImport);
|
||||
};
|
||||
}, [importMnemonic, onBlur]);
|
||||
|
||||
const importMnemonic = async text => {
|
||||
if (clearClipboardMenuState) {
|
||||
try {
|
||||
if (await Clipboard.hasString()) {
|
||||
Clipboard.setString('');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to clear clipboard:', error);
|
||||
}
|
||||
}
|
||||
navigation.navigate('ImportWalletDiscovery', {
|
||||
importText: text,
|
||||
askPassphrase: askPassphraseMenuState,
|
||||
searchAccounts: searchAccountsMenuState,
|
||||
});
|
||||
};
|
||||
const onBarScanned = useCallback(
|
||||
(value: string | { data: any }) => {
|
||||
// no objects here, only strings
|
||||
const newValue: string = typeof value !== 'string' ? value.data + '' : value;
|
||||
setImportText(newValue);
|
||||
setTimeout(() => importMnemonic(newValue), 500);
|
||||
},
|
||||
[importMnemonic],
|
||||
);
|
||||
|
||||
const onBarScanned = value => {
|
||||
if (value && value.data) value = value.data + ''; // no objects here, only strings
|
||||
setImportText(value);
|
||||
setTimeout(() => importMnemonic(value), 500);
|
||||
};
|
||||
|
||||
const importScan = async () => {
|
||||
const data = await scanQrHelper(navigation, true);
|
||||
const importScan = useCallback(async () => {
|
||||
const data = await scanQrHelper(route.name, true);
|
||||
if (data) {
|
||||
onBarScanned(data);
|
||||
}
|
||||
};
|
||||
}, [route.name, onBarScanned]);
|
||||
|
||||
const speedBackdoorTap = () => {
|
||||
setSpeedBackdoor(v => {
|
||||
@ -128,7 +121,7 @@ const WalletsImport = () => {
|
||||
};
|
||||
|
||||
const toolTipOnPressMenuItem = useCallback(
|
||||
menuItem => {
|
||||
(menuItem: string) => {
|
||||
Keyboard.dismiss();
|
||||
if (menuItem === CommonToolTipActions.Passphrase.id) {
|
||||
setAskPassphraseMenuState(!askPassphraseMenuState);
|
||||
@ -143,13 +136,11 @@ const WalletsImport = () => {
|
||||
|
||||
// ToolTipMenu actions for advanced options
|
||||
const toolTipActions = useMemo(() => {
|
||||
const askPassphraseAction = CommonToolTipActions.Passphrase;
|
||||
askPassphraseAction.menuState = askPassphraseMenuState;
|
||||
const searchAccountsAction = CommonToolTipActions.SearchAccount;
|
||||
searchAccountsAction.menuState = searchAccountsMenuState;
|
||||
const clearClipboardAction = CommonToolTipActions.ClearClipboard;
|
||||
clearClipboardAction.menuState = clearClipboardMenuState;
|
||||
return [askPassphraseAction, searchAccountsAction, clearClipboardAction];
|
||||
return [
|
||||
{ ...CommonToolTipActions.Passphrase, menuState: askPassphraseMenuState },
|
||||
{ ...CommonToolTipActions.SearchAccount, menuState: searchAccountsMenuState },
|
||||
{ ...CommonToolTipActions.ClearClipboard, menuState: clearClipboardMenuState },
|
||||
];
|
||||
}, [askPassphraseMenuState, clearClipboardMenuState, searchAccountsMenuState]);
|
||||
|
||||
const HeaderRight = useMemo(
|
||||
@ -157,6 +148,23 @@ const WalletsImport = () => {
|
||||
[toolTipOnPressMenuItem, toolTipActions],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
disallowScreenshot(isPrivacyBlurEnabled);
|
||||
return () => {
|
||||
disallowScreenshot(false);
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerImport) handleImport();
|
||||
}, [triggerImport, handleImport]);
|
||||
|
||||
useEffect(() => {
|
||||
if (scannedData) {
|
||||
onBarScanned(scannedData);
|
||||
}
|
||||
}, [scannedData, onBarScanned]);
|
||||
|
||||
// Adding the ToolTipMenu to the header
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
@ -169,12 +177,7 @@ const WalletsImport = () => {
|
||||
<BlueSpacing20 />
|
||||
<View style={styles.center}>
|
||||
<>
|
||||
<Button
|
||||
disabled={importText.trim().length === 0}
|
||||
title={loc.wallets.import_do_import}
|
||||
testID="DoImport"
|
||||
onPress={importButtonPressed}
|
||||
/>
|
||||
<Button disabled={importText.trim().length === 0} title={loc.wallets.import_do_import} testID="DoImport" onPress={handleImport} />
|
||||
<BlueSpacing20 />
|
||||
<BlueButtonLink title={loc.wallets.import_scan_qr} onPress={importScan} testID="ScanImport" />
|
||||
</>
|
||||
@ -234,4 +237,4 @@ const WalletsImport = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default WalletsImport;
|
||||
export default ImportWallet;
|
@ -19,6 +19,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { THDWalletForWatchOnly, TWallet } from '../../class/wallets/types';
|
||||
import { navigate } from '../../NavigationService';
|
||||
import { keepAwake, disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
|
||||
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
|
||||
@ -34,6 +35,7 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
const { colors } = useTheme();
|
||||
const route = useRoute<RouteProps>();
|
||||
const { importText, askPassphrase, searchAccounts } = route.params;
|
||||
const { isElectrumDisabled } = useSettings();
|
||||
const task = useRef<TImport | null>(null);
|
||||
const { addAndSaveWallet } = useStorage();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
@ -67,6 +69,11 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
[addAndSaveWallet],
|
||||
);
|
||||
|
||||
const handleSave = () => {
|
||||
if (wallets.length === 0) return;
|
||||
saveWallet(wallets[selected].wallet);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const onProgress = (data: string) => setProgress(data);
|
||||
|
||||
@ -105,7 +112,7 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
};
|
||||
|
||||
keepAwake(true);
|
||||
task.current = startImport(importText, askPassphrase, searchAccounts, onProgress, onWallet, onPassword);
|
||||
task.current = startImport(importText, askPassphrase, searchAccounts, isElectrumDisabled, onProgress, onWallet, onPassword);
|
||||
|
||||
task.current.promise
|
||||
.then(({ cancelled, wallets: w }) => {
|
||||
@ -117,6 +124,7 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
})
|
||||
.catch(e => {
|
||||
console.warn('import error', e);
|
||||
console.warn('err.stack', e.stack);
|
||||
presentAlert({ title: 'Import error', message: e.message });
|
||||
})
|
||||
.finally(() => {
|
||||
@ -129,8 +137,9 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
keepAwake(false);
|
||||
task.current?.stop();
|
||||
};
|
||||
// ignoring "navigation" here, because it is constantly mutating
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [askPassphrase, importText, isElectrumDisabled, saveWallet, searchAccounts]);
|
||||
|
||||
const handleCustomDerivation = () => {
|
||||
task.current?.stop();
|
||||
@ -157,16 +166,21 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
const ListHeaderComponent = useMemo(
|
||||
() => (
|
||||
<>
|
||||
{wallets && wallets.length > 0 ? (
|
||||
{wallets.length > 0 ? (
|
||||
<>
|
||||
<BlueSpacing20 />
|
||||
{isElectrumDisabled && (
|
||||
<>
|
||||
<BlueFormLabel>{loc.wallets.import_discovery_offline}</BlueFormLabel>
|
||||
<BlueSpacing20 />
|
||||
</>
|
||||
)}
|
||||
<BlueFormLabel>{loc.wallets.import_discovery_subtitle}</BlueFormLabel>
|
||||
<BlueSpacing10 />
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
[wallets],
|
||||
[wallets, isElectrumDisabled],
|
||||
);
|
||||
|
||||
const ListEmptyComponent = useMemo(
|
||||
@ -213,14 +227,7 @@ const ImportWalletDiscovery: React.FC = () => {
|
||||
)}
|
||||
<BlueSpacing10 />
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button
|
||||
disabled={wallets?.length === 0}
|
||||
title={loc.wallets.import_do_import}
|
||||
onPress={() => {
|
||||
if (wallets.length === 0) return;
|
||||
saveWallet(wallets[selected].wallet);
|
||||
}}
|
||||
/>
|
||||
<Button disabled={wallets?.length === 0} title={loc.wallets.import_do_import} onPress={handleSave} />
|
||||
</View>
|
||||
</View>
|
||||
</SafeArea>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import assert from 'assert';
|
||||
import fs from 'fs';
|
||||
|
||||
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
||||
import {
|
||||
@ -17,7 +18,7 @@ import {
|
||||
WatchOnlyWallet,
|
||||
} from '../../class';
|
||||
import startImport from '../../class/wallet-import';
|
||||
const fs = require('fs');
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
|
||||
jest.setTimeout(90 * 1000);
|
||||
|
||||
@ -32,31 +33,37 @@ beforeAll(async () => {
|
||||
await BlueElectrum.connectMain();
|
||||
});
|
||||
|
||||
const createStore = password => {
|
||||
const state = { wallets: [] };
|
||||
const history = [];
|
||||
type THistoryItem = { action: 'progress'; data: string } | { action: 'wallet'; data: TWallet } | { action: 'password'; data: string };
|
||||
type TState = { wallets: TWallet[]; progress?: string; password?: string };
|
||||
type TOnProgress = (name: string) => void;
|
||||
type TOnWallet = (wallet: TWallet) => void;
|
||||
type TOnPassword = (title: string, text: string) => Promise<string>;
|
||||
|
||||
const onProgress = data => {
|
||||
const createStore = (password?: string) => {
|
||||
const state: TState = { wallets: [] };
|
||||
const history: THistoryItem[] = [];
|
||||
|
||||
const onProgress: TOnProgress = data => {
|
||||
history.push({ action: 'progress', data });
|
||||
state.progress = data;
|
||||
};
|
||||
|
||||
const onWallet = data => {
|
||||
const onWallet: TOnWallet = data => {
|
||||
history.push({ action: 'wallet', data });
|
||||
state.wallets.push(data);
|
||||
};
|
||||
|
||||
const onPassword = () => {
|
||||
history.push({ action: 'password', data: password });
|
||||
const onPassword: TOnPassword = async () => {
|
||||
history.push({ action: 'password', data: password! });
|
||||
state.password = password;
|
||||
return password;
|
||||
return password!;
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
history,
|
||||
callbacks: [onProgress, onWallet, onPassword],
|
||||
};
|
||||
} as const;
|
||||
};
|
||||
|
||||
describe('import procedure', () => {
|
||||
@ -69,8 +76,9 @@ describe('import procedure', () => {
|
||||
return undefined;
|
||||
};
|
||||
const store = createStore();
|
||||
// @ts-ignore: oopsie
|
||||
store.callbacks[2] = onPassword;
|
||||
const { promise } = startImport('6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN', false, false, false, ...store.callbacks);
|
||||
const imprt = await promise;
|
||||
assert.strictEqual(store.state.wallets.length, 0);
|
||||
assert.strictEqual(imprt.cancelled, true);
|
||||
@ -78,7 +86,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can be stopped', async () => {
|
||||
const store = createStore();
|
||||
const { promise, stop } = startImport('KztVRmc2EJJBHi599mCdXrxMTsNsGy3NUjc3Fb3FFDSMYyMDRjnv', false, false, ...store.callbacks);
|
||||
const { promise, stop } = startImport('KztVRmc2EJJBHi599mCdXrxMTsNsGy3NUjc3Fb3FFDSMYyMDRjnv', false, false, false, ...store.callbacks);
|
||||
stop();
|
||||
await assert.doesNotReject(async () => await promise);
|
||||
const imprt = await promise;
|
||||
@ -91,18 +99,33 @@ describe('import procedure', () => {
|
||||
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets.length > 3, true);
|
||||
});
|
||||
|
||||
it('can import multiple wallets in offline mode', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport(
|
||||
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets.length > 100, true);
|
||||
});
|
||||
|
||||
it('can import BIP84', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport(
|
||||
'always direct find escape liar turn differ shy tool gap elder galaxy lawn wild movie fog moon spread casual inner box diagram outdoor tell',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -116,6 +139,7 @@ describe('import procedure', () => {
|
||||
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -125,7 +149,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import Legacy', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport('KztVRmc2EJJBHi599mCdXrxMTsNsGy3NUjc3Fb3FFDSMYyMDRjnv', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('KztVRmc2EJJBHi599mCdXrxMTsNsGy3NUjc3Fb3FFDSMYyMDRjnv', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, LegacyWallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getAddress(), '1AhcdMCzby4VXgqrexuMfh7eiSprRFtN78');
|
||||
@ -133,7 +157,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import P2SH Segwit', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport('L3NxFnYoBGjJ5PhxrxV6jorvjnc8cerYJx71vXU6ta8BXQxHVZya', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('L3NxFnYoBGjJ5PhxrxV6jorvjnc8cerYJx71vXU6ta8BXQxHVZya', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, SegwitP2SHWallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getAddress(), '3KM9VfdsDf9uT7uwZagoKgVn8z35m9CtSM');
|
||||
@ -143,7 +167,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import Bech32 Segwit', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport('L1T6FfKpKHi8JE6eBKrsXkenw34d5FfFzJUZ6dLs2utxkSvsDfxZ', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('L1T6FfKpKHi8JE6eBKrsXkenw34d5FfFzJUZ6dLs2utxkSvsDfxZ', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, SegwitBech32Wallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getAddress(), 'bc1q763rf54hzuncmf8dtlz558uqe4f247mq39rjvr');
|
||||
@ -153,7 +177,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import Legacy/P2SH/Bech32 from an empty wallet', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport('L36mabzoQyMZoHHsBFVNB7PUBXgXTynwY6yR7kYZ82EkS7oejVp2', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('L36mabzoQyMZoHHsBFVNB7PUBXgXTynwY6yR7kYZ82EkS7oejVp2', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, SegwitBech32Wallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getAddress(), 'bc1q8dkdgpaq9sd2xwptsjhe7krwp0k595w0hdtkfr');
|
||||
@ -169,6 +193,7 @@ describe('import procedure', () => {
|
||||
'sting museum endless duty nice riot because swallow brother depth weapon merge woman wish hold finish venture gauge stomach bomb device bracket agent parent',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -182,6 +207,7 @@ describe('import procedure', () => {
|
||||
'abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abeille',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -195,6 +221,7 @@ describe('import procedure', () => {
|
||||
'believe torch sport lizard absurd retreat scale layer song pen clump combine window staff dream filter latin bicycle vapor anchor put clean gain slush',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -208,6 +235,7 @@ describe('import procedure', () => {
|
||||
'eight derive blast guide smoke piece coral burden lottery flower tomato flame',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -221,6 +249,7 @@ describe('import procedure', () => {
|
||||
'receive happy wash prosper update pet neck acid try profit proud hungry',
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -234,6 +263,7 @@ describe('import procedure', () => {
|
||||
'become salmon motor battle sweet merit romance ecology age squirrel oblige awesome',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -248,6 +278,7 @@ describe('import procedure', () => {
|
||||
'noble mimic pipe merry knife screen enter dune crop bonus slice card',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -262,6 +293,7 @@ describe('import procedure', () => {
|
||||
'bitter grass shiver impose acquire brush forget axis eager alone wine silver',
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -275,6 +307,7 @@ describe('import procedure', () => {
|
||||
'abstract rhythm weird food attract treat mosquito sight royal actor surround ride strike remove guilt catch filter summer mushroom protect poverty cruel chaos pattern',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -287,6 +320,7 @@ describe('import procedure', () => {
|
||||
'able mix price funny host express lawsuit congress antique float pig exchange vapor drip wide cup style apple tumble verb fix blush tongue market',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -297,14 +331,14 @@ describe('import procedure', () => {
|
||||
const store = createStore();
|
||||
const tempWallet = new HDSegwitBech32Wallet();
|
||||
await tempWallet.generate();
|
||||
const { promise } = startImport(tempWallet.getSecret(), false, false, ...store.callbacks);
|
||||
const { promise } = startImport(tempWallet.getSecret(), false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, HDSegwitBech32Wallet.type);
|
||||
});
|
||||
|
||||
it('can import Legacy with uncompressed pubkey', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport('5KE6tf9vhYkzYSbgEL6M7xvkY69GMFHF3WxzYaCFMvwMxn3QgRS', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('5KE6tf9vhYkzYSbgEL6M7xvkY69GMFHF3WxzYaCFMvwMxn3QgRS', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].getSecret(), '5KE6tf9vhYkzYSbgEL6M7xvkY69GMFHF3WxzYaCFMvwMxn3QgRS');
|
||||
assert.strictEqual(store.state.wallets[0].type, LegacyWallet.type);
|
||||
@ -313,7 +347,7 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import BIP38 encrypted backup', async () => {
|
||||
const store = createStore('qwerty');
|
||||
const { promise } = startImport('6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN', false, false, ...store.callbacks);
|
||||
const { promise } = startImport('6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN', false, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].getSecret(), 'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc');
|
||||
assert.strictEqual(store.state.wallets[0].type, SegwitBech32Wallet.type);
|
||||
@ -328,17 +362,17 @@ describe('import procedure', () => {
|
||||
|
||||
it('can import watch-only address', async () => {
|
||||
const store1 = createStore();
|
||||
const { promise: promise1 } = startImport('1AhcdMCzby4VXgqrexuMfh7eiSprRFtN78', false, false, ...store1.callbacks);
|
||||
const { promise: promise1 } = startImport('1AhcdMCzby4VXgqrexuMfh7eiSprRFtN78', false, false, false, ...store1.callbacks);
|
||||
await promise1;
|
||||
assert.strictEqual(store1.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
|
||||
const store2 = createStore();
|
||||
const { promise: promise2 } = startImport('3EoqYYp7hQSHn5nHqRtWzkgqmK3caQ2SUu', false, false, ...store2.callbacks);
|
||||
const { promise: promise2 } = startImport('3EoqYYp7hQSHn5nHqRtWzkgqmK3caQ2SUu', false, false, false, ...store2.callbacks);
|
||||
await promise2;
|
||||
assert.strictEqual(store2.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
|
||||
const store3 = createStore();
|
||||
const { promise: promise3 } = startImport('bc1q8j4lk4qlhun0n7h5ahfslfldc8zhlxgynfpdj2', false, false, ...store3.callbacks);
|
||||
const { promise: promise3 } = startImport('bc1q8j4lk4qlhun0n7h5ahfslfldc8zhlxgynfpdj2', false, false, false, ...store3.callbacks);
|
||||
await promise3;
|
||||
assert.strictEqual(store3.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
|
||||
@ -347,6 +381,7 @@ describe('import procedure', () => {
|
||||
'zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store4.callbacks,
|
||||
);
|
||||
await promise4;
|
||||
@ -364,6 +399,7 @@ describe('import procedure', () => {
|
||||
'crystal lungs academic agency class payment actress avoid rebound ordinary exchange petition tendency mild mobile spine robin fancy shelter increase',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -381,6 +417,7 @@ describe('import procedure', () => {
|
||||
'crystal lungs academic agency class payment actress avoid rebound ordinary exchange petition tendency mild mobile spine robin fancy shelter increase',
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -394,6 +431,7 @@ describe('import procedure', () => {
|
||||
'{"ExtPubKey":"zpub6riZchHnrWzhhZ3Z4dhCJmesGyafMmZBRC9txhnidR313XJbcv4KiDubderKHhL7rMsqacYd82FQ38e4whgs8Dg7CpsxX3dSGWayXsEerF4","MasterFingerprint":"7D2F0272","AccountKeyPath":"84\'\\/0\'\\/0\'","CoboVaultFirmwareVersion":"2.6.1(BTC-Only)"}',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -408,6 +446,7 @@ describe('import procedure', () => {
|
||||
`[{"ExtPubKey":"zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs","MasterFingerprint":"73C5DA0A","AccountKeyPath":"m/84'/0'/0'"},{"ExtPubKey":"ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP","MasterFingerprint":"73C5DA0A","AccountKeyPath":"m/49'/0'/0'"},{"ExtPubKey":"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj","MasterFingerprint":"73C5DA0A","AccountKeyPath":"m/44'/0'/0'"}]`,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -442,6 +481,7 @@ describe('import procedure', () => {
|
||||
'{"ExtPubKey":"zpub6qT7amLcp2exr4mU4AhXZMjD9CFkopECVhUxc9LHW8pNsJG2B9ogs5sFbGZpxEeT5TBjLmc7EFYgZA9EeWEM1xkJMFLefzZc8eigRFhKB8Q","MasterFingerprint":"01EBDA7D","AccountKeyPath":"m/84\'/0\'/0\'"}',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -456,6 +496,7 @@ describe('import procedure', () => {
|
||||
'trip ener cloc puls hams ghos inha crow inju vibr seve chro',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store1.callbacks,
|
||||
);
|
||||
await promise1;
|
||||
@ -470,6 +511,7 @@ describe('import procedure', () => {
|
||||
'docu gosp razo chao nort ches nomi fati swam firs deca boy icon virt gap prep seri anch',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store2.callbacks,
|
||||
);
|
||||
await promise2;
|
||||
@ -484,6 +526,7 @@ describe('import procedure', () => {
|
||||
'rece own flig sent tide hood sile bunk deri mana wink belt loud apol mons pill raw gate hurd matc nigh wish todd achi',
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store3.callbacks,
|
||||
);
|
||||
await promise3;
|
||||
@ -500,7 +543,7 @@ describe('import procedure', () => {
|
||||
}
|
||||
|
||||
const store = createStore('1');
|
||||
const { promise } = startImport(process.env.BIP47_HD_MNEMONIC.split(':')[0], true, false, ...store.callbacks);
|
||||
const { promise } = startImport(process.env.BIP47_HD_MNEMONIC.split(':')[0], true, false, false, ...store.callbacks);
|
||||
await promise;
|
||||
assert.strictEqual(store.state.wallets[0].type, HDLegacyP2PKHWallet.type);
|
||||
assert.strictEqual(store.state.wallets[1].type, HDSegwitBech32Wallet.type);
|
||||
@ -513,6 +556,7 @@ describe('import procedure', () => {
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/descriptor.txt').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -530,6 +574,7 @@ describe('import procedure', () => {
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/new-wasabi.json').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
@ -547,6 +592,7 @@ describe('import procedure', () => {
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/sparrow-export.json').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
Loading…
Reference in New Issue
Block a user