2018-07-22 16:49:59 +02:00
|
|
|
/* global alert */
|
|
|
|
import {
|
|
|
|
SegwitP2SHWallet,
|
|
|
|
LegacyWallet,
|
|
|
|
WatchOnlyWallet,
|
|
|
|
HDLegacyBreadwalletWallet,
|
|
|
|
HDSegwitP2SHWallet,
|
|
|
|
HDLegacyP2PKHWallet,
|
|
|
|
} from '../../class';
|
|
|
|
import React, { Component } from 'react';
|
2018-12-11 23:52:46 +01:00
|
|
|
import { KeyboardAvoidingView, Dimensions, View, TouchableWithoutFeedback, Keyboard } from 'react-native';
|
2018-07-22 16:49:59 +02:00
|
|
|
import {
|
|
|
|
BlueFormMultiInput,
|
|
|
|
BlueButtonLink,
|
|
|
|
BlueFormLabel,
|
2018-07-28 21:14:08 +02:00
|
|
|
BlueLoading,
|
2018-07-22 16:49:59 +02:00
|
|
|
BlueButton,
|
|
|
|
SafeBlueArea,
|
2018-10-23 00:51:30 +02:00
|
|
|
BlueSpacing20,
|
2018-07-22 16:49:59 +02:00
|
|
|
BlueHeaderDefaultSub,
|
|
|
|
} from '../../BlueComponents';
|
|
|
|
import PropTypes from 'prop-types';
|
2018-09-01 01:28:19 +02:00
|
|
|
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
|
2018-12-13 17:50:18 +01:00
|
|
|
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
2018-07-22 16:49:59 +02:00
|
|
|
let EV = require('../../events');
|
|
|
|
let A = require('../../analytics');
|
|
|
|
/** @type {AppStorage} */
|
|
|
|
let BlueApp = require('../../BlueApp');
|
|
|
|
let loc = require('../../loc');
|
|
|
|
const { width } = Dimensions.get('window');
|
|
|
|
|
|
|
|
export default class WalletsImport extends Component {
|
|
|
|
static navigationOptions = {
|
2018-09-19 03:59:16 +02:00
|
|
|
header: ({ navigation }) => {
|
|
|
|
return <BlueHeaderDefaultSub leftText={loc.wallets.import.title} onClose={() => navigation.goBack(null)} />;
|
|
|
|
},
|
2018-07-22 16:49:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
isLoading: true,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async componentDidMount() {
|
|
|
|
this.setState({
|
|
|
|
isLoading: false,
|
|
|
|
label: '',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async _saveWallet(w) {
|
2018-07-28 21:14:08 +02:00
|
|
|
alert(loc.wallets.import.success);
|
2018-12-13 17:50:18 +01:00
|
|
|
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
2018-07-28 21:14:08 +02:00
|
|
|
w.setLabel(loc.wallets.import.imported + ' ' + w.getTypeReadable());
|
2018-07-22 16:49:59 +02:00
|
|
|
BlueApp.wallets.push(w);
|
|
|
|
await BlueApp.saveToDisk();
|
|
|
|
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
|
|
|
A(A.ENUM.CREATED_WALLET);
|
|
|
|
setTimeout(() => {
|
|
|
|
this.props.navigation.popToTop();
|
|
|
|
}, 500);
|
|
|
|
}
|
|
|
|
|
|
|
|
async importMnemonic(text) {
|
|
|
|
try {
|
2018-09-01 01:28:19 +02:00
|
|
|
// is it lightning custodian?
|
2018-12-11 23:52:46 +01:00
|
|
|
if (text.indexOf('blitzhub://') !== -1 || text.indexOf('lndhub://') !== -1) {
|
2018-09-01 01:28:19 +02:00
|
|
|
// yep its lnd
|
|
|
|
for (let t of BlueApp.getWallets()) {
|
|
|
|
if (t.type === new LightningCustodianWallet().type) {
|
|
|
|
// already exist
|
|
|
|
return alert('Only 1 Ligthning wallet allowed for now');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let lnd = new LightningCustodianWallet();
|
|
|
|
lnd.setSecret(text);
|
|
|
|
await lnd.authorize();
|
|
|
|
await lnd.fetchTransactions();
|
|
|
|
await lnd.fetchBalance();
|
|
|
|
return this._saveWallet(lnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// trying other wallet types
|
|
|
|
|
2018-07-22 16:49:59 +02:00
|
|
|
let segwitWallet = new SegwitP2SHWallet();
|
|
|
|
segwitWallet.setSecret(text);
|
|
|
|
if (segwitWallet.getAddress()) {
|
|
|
|
// ok its a valid WIF
|
|
|
|
|
|
|
|
let legacyWallet = new LegacyWallet();
|
|
|
|
legacyWallet.setSecret(text);
|
|
|
|
|
|
|
|
await legacyWallet.fetchBalance();
|
|
|
|
if (legacyWallet.getBalance() > 0) {
|
|
|
|
// yep, its legacy we're importing
|
|
|
|
await legacyWallet.fetchTransactions();
|
|
|
|
return this._saveWallet(legacyWallet);
|
|
|
|
} else {
|
|
|
|
// by default, we import wif as Segwit P2SH
|
|
|
|
await segwitWallet.fetchBalance();
|
|
|
|
await segwitWallet.fetchTransactions();
|
|
|
|
return this._saveWallet(segwitWallet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we're here - nope, its not a valid WIF
|
|
|
|
|
|
|
|
let hd1 = new HDLegacyBreadwalletWallet();
|
|
|
|
hd1.setSecret(text);
|
|
|
|
if (hd1.validateMnemonic()) {
|
|
|
|
await hd1.fetchBalance();
|
|
|
|
if (hd1.getBalance() > 0) {
|
|
|
|
await hd1.fetchTransactions();
|
|
|
|
return this._saveWallet(hd1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let hd2 = new HDSegwitP2SHWallet();
|
|
|
|
hd2.setSecret(text);
|
|
|
|
if (hd2.validateMnemonic()) {
|
|
|
|
await hd2.fetchBalance();
|
|
|
|
if (hd2.getBalance() > 0) {
|
|
|
|
await hd2.fetchTransactions();
|
|
|
|
return this._saveWallet(hd2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let hd3 = new HDLegacyP2PKHWallet();
|
|
|
|
hd3.setSecret(text);
|
|
|
|
if (hd3.validateMnemonic()) {
|
|
|
|
await hd3.fetchBalance();
|
|
|
|
if (hd3.getBalance() > 0) {
|
|
|
|
await hd3.fetchTransactions();
|
|
|
|
return this._saveWallet(hd3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// no balances? how about transactions count?
|
|
|
|
|
|
|
|
if (hd1.validateMnemonic()) {
|
|
|
|
await hd1.fetchTransactions();
|
|
|
|
if (hd1.getTransactions().length !== 0) {
|
|
|
|
return this._saveWallet(hd1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hd2.validateMnemonic()) {
|
|
|
|
await hd2.fetchTransactions();
|
|
|
|
if (hd2.getTransactions().length !== 0) {
|
|
|
|
return this._saveWallet(hd2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hd3.validateMnemonic()) {
|
|
|
|
await hd3.fetchTransactions();
|
|
|
|
if (hd3.getTransactions().length !== 0) {
|
|
|
|
return this._saveWallet(hd3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// is it even valid? if yes we will import as:
|
|
|
|
if (hd2.validateMnemonic()) {
|
|
|
|
return this._saveWallet(hd2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// not valid? maybe its a watch-only address?
|
|
|
|
|
|
|
|
let watchOnly = new WatchOnlyWallet();
|
|
|
|
watchOnly.setSecret(text);
|
|
|
|
if (watchOnly.valid()) {
|
|
|
|
await watchOnly.fetchTransactions();
|
|
|
|
await watchOnly.fetchBalance();
|
|
|
|
return this._saveWallet(watchOnly);
|
|
|
|
}
|
|
|
|
|
|
|
|
// nope?
|
|
|
|
|
|
|
|
// TODO: try a raw private key
|
|
|
|
} catch (Err) {
|
|
|
|
console.warn(Err);
|
|
|
|
}
|
|
|
|
|
2018-07-28 21:14:08 +02:00
|
|
|
alert(loc.wallets.import.error);
|
2018-12-13 17:50:18 +01:00
|
|
|
ReactNativeHapticFeedback.trigger('notificationError', false);
|
2018-07-28 21:14:08 +02:00
|
|
|
// Plan:
|
2018-07-22 16:49:59 +02:00
|
|
|
// 1. check if its HDSegwitP2SHWallet (BIP49)
|
|
|
|
// 2. check if its HDLegacyP2PKHWallet (BIP44)
|
|
|
|
// 3. check if its HDLegacyBreadwalletWallet (no BIP, just "m/0")
|
|
|
|
// 4. check if its Segwit WIF (P2SH)
|
|
|
|
// 5. check if its Legacy WIF
|
|
|
|
// 6. check if its address (watch-only wallet)
|
2018-07-28 21:14:08 +02:00
|
|
|
// 7. check if its private key (segwit address P2SH) TODO
|
|
|
|
// 7. check if its private key (legacy address) TODO
|
2018-07-22 16:49:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setLabel(text) {
|
|
|
|
this.setState({
|
|
|
|
label: text,
|
|
|
|
}); /* also, a hack to make screen update new typed text */
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
if (this.state.isLoading) {
|
|
|
|
return (
|
|
|
|
<View style={{ flex: 1, paddingTop: 20 }}>
|
2018-07-28 21:14:08 +02:00
|
|
|
<BlueLoading />
|
2018-07-22 16:49:59 +02:00
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1, paddingTop: 40 }}>
|
2018-12-11 23:52:46 +01:00
|
|
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
|
|
|
<KeyboardAvoidingView behavior="position" enabled>
|
|
|
|
<BlueFormLabel>{loc.wallets.import.explanation}</BlueFormLabel>
|
|
|
|
<BlueSpacing20 />
|
|
|
|
<BlueFormMultiInput
|
|
|
|
value={this.state.label}
|
|
|
|
placeholder={''}
|
|
|
|
onChangeText={text => {
|
|
|
|
this.setLabel(text);
|
2018-07-22 16:49:59 +02:00
|
|
|
}}
|
|
|
|
/>
|
2018-12-11 23:52:46 +01:00
|
|
|
<BlueSpacing20 />
|
|
|
|
<View
|
|
|
|
style={{
|
|
|
|
alignItems: 'center',
|
2018-07-22 16:49:59 +02:00
|
|
|
}}
|
2018-12-11 23:52:46 +01:00
|
|
|
>
|
|
|
|
<BlueButton
|
|
|
|
title={loc.wallets.import.do_import}
|
|
|
|
buttonStyle={{
|
|
|
|
width: width / 1.5,
|
|
|
|
}}
|
|
|
|
onPress={async () => {
|
|
|
|
if (!this.state.label) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.setState({ isLoading: true });
|
|
|
|
setTimeout(async () => {
|
|
|
|
await this.importMnemonic(this.state.label.trim());
|
|
|
|
this.setState({ isLoading: false });
|
|
|
|
}, 1);
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<BlueButtonLink
|
|
|
|
title={loc.wallets.import.scan_qr}
|
|
|
|
onPress={() => {
|
|
|
|
this.props.navigation.navigate('ScanQrWif');
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
</KeyboardAvoidingView>
|
|
|
|
</TouchableWithoutFeedback>
|
2018-07-22 16:49:59 +02:00
|
|
|
</SafeBlueArea>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WalletsImport.propTypes = {
|
|
|
|
navigation: PropTypes.shape({
|
|
|
|
navigate: PropTypes.func,
|
|
|
|
popToTop: PropTypes.func,
|
|
|
|
goBack: PropTypes.func,
|
|
|
|
}),
|
|
|
|
};
|