2019-09-27 16:49:56 +02:00
|
|
|
/* global alert */
|
|
|
|
import React, { Component } from 'react';
|
2020-01-01 04:31:04 +01:00
|
|
|
import {
|
|
|
|
ActivityIndicator,
|
|
|
|
TouchableOpacity,
|
|
|
|
ScrollView,
|
|
|
|
View,
|
|
|
|
Dimensions,
|
|
|
|
TextInput,
|
|
|
|
Linking,
|
|
|
|
Platform,
|
2020-01-15 05:49:57 +01:00
|
|
|
PermissionsAndroid,
|
2020-08-16 04:43:17 +02:00
|
|
|
Text,
|
2020-05-24 11:17:26 +02:00
|
|
|
StyleSheet,
|
2020-01-01 04:31:04 +01:00
|
|
|
} from 'react-native';
|
2020-08-16 04:43:17 +02:00
|
|
|
import ImagePicker from 'react-native-image-picker';
|
2020-06-09 23:02:25 +02:00
|
|
|
import Clipboard from '@react-native-community/clipboard';
|
2019-09-27 16:49:56 +02:00
|
|
|
import {
|
|
|
|
BlueButton,
|
2020-07-15 19:32:59 +02:00
|
|
|
SecondButton,
|
2019-09-27 16:49:56 +02:00
|
|
|
BlueText,
|
|
|
|
SafeBlueArea,
|
|
|
|
BlueCard,
|
|
|
|
BlueNavigationStyle,
|
|
|
|
BlueSpacing20,
|
|
|
|
BlueCopyToClipboardButton,
|
2020-04-28 18:27:35 +02:00
|
|
|
BlueBigCheckmark,
|
2020-06-24 13:56:35 +02:00
|
|
|
DynamicQRCode,
|
2019-09-27 16:49:56 +02:00
|
|
|
} from '../../BlueComponents';
|
|
|
|
import PropTypes from 'prop-types';
|
2020-01-01 04:31:04 +01:00
|
|
|
import Share from 'react-native-share';
|
2020-08-16 04:43:17 +02:00
|
|
|
import { getSystemName } from 'react-native-device-info';
|
2019-09-27 16:49:56 +02:00
|
|
|
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
2020-01-01 04:31:04 +01:00
|
|
|
import RNFS from 'react-native-fs';
|
|
|
|
import DocumentPicker from 'react-native-document-picker';
|
2020-06-24 13:56:35 +02:00
|
|
|
import { decodeUR, extractSingleWorkload } from 'bc-ur/dist';
|
|
|
|
import { Psbt } from 'bitcoinjs-lib';
|
2020-07-20 15:38:46 +02:00
|
|
|
import loc from '../../loc';
|
2020-07-15 19:32:59 +02:00
|
|
|
import { BlueCurrentTheme } from '../../components/themes';
|
2020-07-01 13:56:52 +02:00
|
|
|
const EV = require('../../blue_modules/events');
|
|
|
|
const BlueElectrum = require('../../blue_modules/BlueElectrum');
|
2019-09-27 16:49:56 +02:00
|
|
|
/** @type {AppStorage} */
|
|
|
|
const BlueApp = require('../../BlueApp');
|
|
|
|
const bitcoin = require('bitcoinjs-lib');
|
2020-07-28 15:49:48 +02:00
|
|
|
const notifications = require('../../blue_modules/notifications');
|
2020-08-16 04:43:17 +02:00
|
|
|
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
2019-09-27 16:49:56 +02:00
|
|
|
const { height, width } = Dimensions.get('window');
|
2020-08-16 04:43:17 +02:00
|
|
|
const isDesktop = getSystemName() === 'Mac OS X';
|
2020-05-24 11:17:26 +02:00
|
|
|
const styles = StyleSheet.create({
|
|
|
|
root: {
|
|
|
|
flex: 1,
|
2020-07-15 19:32:59 +02:00
|
|
|
backgroundColor: BlueCurrentTheme.colors.elevated,
|
2020-05-24 11:17:26 +02:00
|
|
|
},
|
|
|
|
scrollViewContent: {
|
|
|
|
flexGrow: 1,
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
},
|
|
|
|
container: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
justifyContent: 'center',
|
|
|
|
paddingTop: 16,
|
|
|
|
paddingBottom: 16,
|
|
|
|
},
|
|
|
|
rootCamera: {
|
|
|
|
flex: 1,
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
},
|
|
|
|
rootPadding: {
|
|
|
|
flex: 1,
|
|
|
|
paddingTop: 20,
|
|
|
|
},
|
|
|
|
closeCamera: {
|
|
|
|
width: 40,
|
|
|
|
height: 40,
|
|
|
|
backgroundColor: 'rgba(0,0,0,0.4)',
|
|
|
|
justifyContent: 'center',
|
|
|
|
borderRadius: 20,
|
|
|
|
position: 'absolute',
|
|
|
|
right: 16,
|
|
|
|
top: 64,
|
|
|
|
},
|
|
|
|
closeCameraImage: {
|
|
|
|
alignSelf: 'center',
|
|
|
|
},
|
|
|
|
blueBigCheckmark: {
|
|
|
|
marginTop: 143,
|
|
|
|
marginBottom: 53,
|
|
|
|
},
|
|
|
|
hexWrap: {
|
|
|
|
alignItems: 'center',
|
|
|
|
flex: 1,
|
|
|
|
},
|
|
|
|
hexLabel: {
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.foregroundColor,
|
2020-05-24 11:17:26 +02:00
|
|
|
fontWeight: '500',
|
|
|
|
},
|
|
|
|
hexInput: {
|
2020-07-15 19:32:59 +02:00
|
|
|
borderColor: BlueCurrentTheme.colors.formBorder,
|
|
|
|
backgroundColor: BlueCurrentTheme.colors.inputBackgroundColor,
|
2020-05-24 11:17:26 +02:00
|
|
|
borderRadius: 4,
|
|
|
|
marginTop: 20,
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.foregroundColor,
|
2020-05-24 11:17:26 +02:00
|
|
|
fontWeight: '500',
|
|
|
|
fontSize: 14,
|
|
|
|
paddingHorizontal: 16,
|
|
|
|
paddingBottom: 16,
|
|
|
|
paddingTop: 16,
|
|
|
|
},
|
|
|
|
hexTouch: {
|
|
|
|
marginVertical: 24,
|
|
|
|
},
|
|
|
|
hexText: {
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.foregroundColor,
|
2020-05-24 11:17:26 +02:00
|
|
|
fontSize: 15,
|
|
|
|
fontWeight: '500',
|
|
|
|
alignSelf: 'center',
|
|
|
|
},
|
|
|
|
copyToClipboard: {
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2019-09-27 16:49:56 +02:00
|
|
|
export default class PsbtWithHardwareWallet extends Component {
|
|
|
|
cameraRef = null;
|
|
|
|
|
2020-06-24 13:56:35 +02:00
|
|
|
_onReadUniformResource = ur => {
|
|
|
|
try {
|
|
|
|
const [index, total] = extractSingleWorkload(ur);
|
|
|
|
const { animatedQRCodeData } = this.state;
|
|
|
|
if (animatedQRCodeData.length > 0) {
|
|
|
|
const currentTotal = animatedQRCodeData[0].total;
|
|
|
|
if (total !== currentTotal) {
|
|
|
|
alert('invalid animated QRCode');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!animatedQRCodeData.find(i => i.index === index)) {
|
|
|
|
this.setState(
|
|
|
|
state => ({
|
|
|
|
animatedQRCodeData: [
|
|
|
|
...state.animatedQRCodeData,
|
|
|
|
{
|
|
|
|
index,
|
|
|
|
total,
|
|
|
|
data: ur,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}),
|
|
|
|
() => {
|
|
|
|
if (this.state.animatedQRCodeData.length === total) {
|
2020-08-16 04:43:17 +02:00
|
|
|
const payload = decodeUR(this.state.animatedQRCodeData.map(i => i.data));
|
|
|
|
const psbtB64 = Buffer.from(payload, 'hex').toString('base64');
|
|
|
|
const psbt = Psbt.fromBase64(psbtB64);
|
|
|
|
this.setState({ txhex: psbt.extractTransaction().toHex() });
|
2020-06-24 13:56:35 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} catch (Err) {
|
|
|
|
alert('invalid animated QRCode fragment, please try again');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
_combinePSBT = receivedPSBT => {
|
|
|
|
return this.state.fromWallet.combinePsbt(
|
|
|
|
this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64(),
|
|
|
|
receivedPSBT,
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-08-16 05:35:28 +02:00
|
|
|
onBarScanned = ret => {
|
2020-06-24 13:56:35 +02:00
|
|
|
if (ret.data.toUpperCase().startsWith('UR')) {
|
|
|
|
return this._onReadUniformResource(ret.data);
|
|
|
|
}
|
2020-02-24 22:45:14 +01:00
|
|
|
if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) {
|
|
|
|
// this looks like NOT base64, so maybe its transaction's hex
|
2020-08-16 05:35:28 +02:00
|
|
|
this.setState({ txhex: ret.data }, () => this.props.navigation.dangerouslyGetParent().pop());
|
2020-02-24 22:45:14 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-08-16 04:43:17 +02:00
|
|
|
try {
|
|
|
|
const Tx = this._combinePSBT(ret.data);
|
|
|
|
this.setState({ txhex: Tx.toHex() });
|
|
|
|
} catch (Err) {
|
|
|
|
alert(Err);
|
|
|
|
}
|
2019-09-27 16:49:56 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
isLoading: false,
|
2020-01-01 04:31:04 +01:00
|
|
|
qrCodeHeight: height > width ? width - 40 : width / 3,
|
2020-05-27 13:12:17 +02:00
|
|
|
memo: props.route.params.memo,
|
|
|
|
psbt: props.route.params.psbt,
|
|
|
|
fromWallet: props.route.params.fromWallet,
|
|
|
|
isFirstPSBTAlreadyBase64: props.route.params.isFirstPSBTAlreadyBase64,
|
2020-01-01 04:31:04 +01:00
|
|
|
isSecondPSBTAlreadyBase64: false,
|
2020-01-03 05:02:41 +01:00
|
|
|
deepLinkPSBT: undefined,
|
2020-05-27 13:12:17 +02:00
|
|
|
txhex: props.route.params.txhex || undefined,
|
2020-06-24 13:56:35 +02:00
|
|
|
animatedQRCodeData: [],
|
2019-09-27 16:49:56 +02:00
|
|
|
};
|
2020-01-15 05:49:57 +01:00
|
|
|
this.fileName = `${Date.now()}.psbt`;
|
2019-09-27 16:49:56 +02:00
|
|
|
}
|
|
|
|
|
2020-01-03 05:02:41 +01:00
|
|
|
static getDerivedStateFromProps(nextProps, prevState) {
|
2020-05-28 11:53:14 +02:00
|
|
|
const deepLinkPSBT = nextProps.route.params.deepLinkPSBT;
|
|
|
|
const txhex = nextProps.route.params.txhex;
|
2020-01-03 05:02:41 +01:00
|
|
|
if (deepLinkPSBT) {
|
|
|
|
try {
|
2020-06-01 14:54:23 +02:00
|
|
|
const Tx = prevState.fromWallet.combinePsbt(
|
2020-01-03 05:02:41 +01:00
|
|
|
prevState.isFirstPSBTAlreadyBase64 ? prevState.psbt : prevState.psbt.toBase64(),
|
|
|
|
deepLinkPSBT,
|
|
|
|
);
|
|
|
|
return {
|
|
|
|
...prevState,
|
|
|
|
txhex: Tx.toHex(),
|
|
|
|
};
|
|
|
|
} catch (Err) {
|
|
|
|
alert(Err);
|
|
|
|
}
|
2020-01-04 04:12:29 +01:00
|
|
|
} else if (txhex) {
|
|
|
|
return {
|
|
|
|
...prevState,
|
|
|
|
txhex: txhex,
|
|
|
|
};
|
2020-01-03 05:02:41 +01:00
|
|
|
}
|
|
|
|
return prevState;
|
|
|
|
}
|
|
|
|
|
2020-01-01 04:31:04 +01:00
|
|
|
componentDidMount() {
|
2019-09-27 16:49:56 +02:00
|
|
|
console.log('send/psbtWithHardwareWallet - componentDidMount');
|
|
|
|
}
|
|
|
|
|
2019-11-02 23:51:33 +01:00
|
|
|
broadcast = () => {
|
2019-09-27 16:49:56 +02:00
|
|
|
this.setState({ isLoading: true }, async () => {
|
|
|
|
try {
|
|
|
|
await BlueElectrum.ping();
|
|
|
|
await BlueElectrum.waitTillConnected();
|
2020-06-01 14:54:23 +02:00
|
|
|
const result = await this.state.fromWallet.broadcastTx(this.state.txhex);
|
2019-09-27 16:49:56 +02:00
|
|
|
if (result) {
|
|
|
|
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
|
|
|
|
this.setState({ success: true, isLoading: false });
|
2020-07-28 15:49:48 +02:00
|
|
|
const txDecoded = bitcoin.Transaction.fromHex(this.state.txhex);
|
|
|
|
const txid = txDecoded.getId();
|
|
|
|
notifications.majorTomToGroundControl([], [], [txid]);
|
2019-09-27 16:49:56 +02:00
|
|
|
if (this.state.memo) {
|
|
|
|
BlueApp.tx_metadata[txid] = { memo: this.state.memo };
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
|
|
|
|
this.setState({ isLoading: false });
|
2020-07-20 15:38:46 +02:00
|
|
|
alert(loc.errors.broadcast);
|
2019-09-27 16:49:56 +02:00
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
|
|
|
|
this.setState({ isLoading: false });
|
|
|
|
alert(error.message);
|
|
|
|
}
|
|
|
|
});
|
2019-11-02 23:51:33 +01:00
|
|
|
};
|
2019-09-27 16:49:56 +02:00
|
|
|
|
|
|
|
_renderSuccess() {
|
|
|
|
return (
|
2020-05-24 11:17:26 +02:00
|
|
|
<SafeBlueArea style={styles.root}>
|
|
|
|
<BlueBigCheckmark style={styles.blueBigCheckmark} />
|
2019-09-27 16:49:56 +02:00
|
|
|
<BlueCard>
|
2020-07-20 15:38:46 +02:00
|
|
|
<BlueButton onPress={() => this.props.navigation.dangerouslyGetParent().pop()} title={loc.send.success_done} />
|
2019-09-27 16:49:56 +02:00
|
|
|
</BlueCard>
|
|
|
|
</SafeBlueArea>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderBroadcastHex() {
|
|
|
|
return (
|
2020-05-24 11:17:26 +02:00
|
|
|
<View style={styles.rootPadding}>
|
|
|
|
<BlueCard style={styles.hexWrap}>
|
2020-07-20 15:38:46 +02:00
|
|
|
<BlueText style={styles.hexLabel}>{loc.send.create_this_is_hex}</BlueText>
|
2020-05-24 11:17:26 +02:00
|
|
|
<TextInput style={styles.hexInput} height={112} multiline editable value={this.state.txhex} />
|
2019-09-27 16:49:56 +02:00
|
|
|
|
2020-05-24 11:17:26 +02:00
|
|
|
<TouchableOpacity style={styles.hexTouch} onPress={() => Clipboard.setString(this.state.txhex)}>
|
2020-07-20 15:38:46 +02:00
|
|
|
<Text style={styles.hexText}>{loc.send.create_copy}</Text>
|
2019-09-27 16:49:56 +02:00
|
|
|
</TouchableOpacity>
|
2020-05-24 11:17:26 +02:00
|
|
|
<TouchableOpacity style={styles.hexTouch} onPress={() => Linking.openURL('https://coinb.in/?verify=' + this.state.txhex)}>
|
2020-07-20 15:38:46 +02:00
|
|
|
<Text style={styles.hexText}>{loc.send.create_verify}</Text>
|
2019-09-27 16:49:56 +02:00
|
|
|
</TouchableOpacity>
|
|
|
|
<BlueSpacing20 />
|
2020-07-20 15:38:46 +02:00
|
|
|
<SecondButton onPress={this.broadcast} title={loc.send.confirm_sendNow} />
|
2019-09-27 16:49:56 +02:00
|
|
|
</BlueCard>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-01 04:31:04 +01:00
|
|
|
exportPSBT = async () => {
|
|
|
|
if (Platform.OS === 'ios') {
|
2020-01-15 05:49:57 +01:00
|
|
|
const filePath = RNFS.TemporaryDirectoryPath + `/${this.fileName}`;
|
2020-01-03 05:02:41 +01:00
|
|
|
await RNFS.writeFile(filePath, this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64());
|
2020-01-01 04:31:04 +01:00
|
|
|
Share.open({
|
|
|
|
url: 'file://' + filePath,
|
|
|
|
})
|
|
|
|
.catch(error => console.log(error))
|
|
|
|
.finally(() => {
|
|
|
|
RNFS.unlink(filePath);
|
|
|
|
});
|
|
|
|
} else if (Platform.OS === 'android') {
|
2020-01-15 05:49:57 +01:00
|
|
|
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
|
2020-07-20 15:38:46 +02:00
|
|
|
title: loc.send.permission_storage_title,
|
|
|
|
message: loc.send.permission_storage_message,
|
|
|
|
buttonNeutral: loc.send.permission_storage_later,
|
|
|
|
buttonNegative: loc._.cancel,
|
|
|
|
buttonPositive: loc._.ok,
|
2020-01-15 05:49:57 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
|
|
|
|
console.log('Storage Permission: Granted');
|
2020-08-16 04:43:17 +02:00
|
|
|
const filePath = RNFS.DownloadDirectoryPath + `/${this.fileName}`;
|
2020-01-15 05:49:57 +01:00
|
|
|
await RNFS.writeFile(filePath, this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64());
|
2020-08-16 04:43:17 +02:00
|
|
|
alert(loc.formatString(loc.send.txSaved, { filePath: this.fileName }));
|
2020-01-15 05:49:57 +01:00
|
|
|
} else {
|
|
|
|
console.log('Storage Permission: Denied');
|
|
|
|
}
|
2020-01-01 04:31:04 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
openSignedTransaction = async () => {
|
|
|
|
try {
|
2020-02-24 22:45:14 +01:00
|
|
|
const res = await DocumentPicker.pick({
|
|
|
|
type: Platform.OS === 'ios' ? ['io.bluewallet.psbt', 'io.bluewallt.psbt.txn'] : [DocumentPicker.types.allFiles],
|
|
|
|
});
|
2020-01-03 05:02:41 +01:00
|
|
|
const file = await RNFS.readFile(res.uri);
|
|
|
|
if (file) {
|
2020-08-16 05:35:28 +02:00
|
|
|
this.setState({ isSecondPSBTAlreadyBase64: true }, () => this.onBarScanned({ data: file }));
|
2020-01-01 04:31:04 +01:00
|
|
|
} else {
|
|
|
|
this.setState({ isSecondPSBTAlreadyBase64: false });
|
|
|
|
throw new Error();
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
if (!DocumentPicker.isCancel(err)) {
|
2020-07-20 15:38:46 +02:00
|
|
|
alert(loc.send.details_no_signed_tx);
|
2020-01-01 04:31:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-16 04:43:17 +02:00
|
|
|
openScanner = () => {
|
|
|
|
if (isDesktop) {
|
|
|
|
ImagePicker.launchCamera(
|
|
|
|
{
|
|
|
|
title: null,
|
|
|
|
mediaType: 'photo',
|
|
|
|
takePhotoButtonTitle: null,
|
|
|
|
},
|
|
|
|
response => {
|
|
|
|
if (response.uri) {
|
|
|
|
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
|
|
|
|
LocalQRCode.decode(uri, (error, result) => {
|
|
|
|
if (!error) {
|
|
|
|
this.onBarScanned(result);
|
|
|
|
} else {
|
|
|
|
alert(loc.send.qr_error_no_qrcode);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
this.props.navigation.navigate('ScanQRCodeRoot', {
|
|
|
|
screen: 'ScanQRCode',
|
|
|
|
params: {
|
|
|
|
onBarScanned: this.onBarScanned,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-09-27 16:49:56 +02:00
|
|
|
render() {
|
|
|
|
if (this.state.isLoading) {
|
|
|
|
return (
|
2020-05-24 11:17:26 +02:00
|
|
|
<View style={styles.rootPadding}>
|
2019-09-27 16:49:56 +02:00
|
|
|
<ActivityIndicator />
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.state.success) return this._renderSuccess();
|
|
|
|
if (this.state.txhex) return this._renderBroadcastHex();
|
|
|
|
|
|
|
|
return (
|
2020-05-24 11:17:26 +02:00
|
|
|
<SafeBlueArea style={styles.root}>
|
|
|
|
<ScrollView centerContent contentContainerStyle={styles.scrollViewContent}>
|
|
|
|
<View style={styles.container}>
|
2019-09-27 16:49:56 +02:00
|
|
|
<BlueCard>
|
2020-07-20 15:38:46 +02:00
|
|
|
<BlueText testID="TextHelperForPSBT">{loc.send.psbt_this_is_psbt}</BlueText>
|
2019-09-27 16:49:56 +02:00
|
|
|
<BlueSpacing20 />
|
2020-06-24 13:56:35 +02:00
|
|
|
<DynamicQRCode value={this.state.psbt.toHex()} capacity={200} />
|
2019-09-27 16:49:56 +02:00
|
|
|
<BlueSpacing20 />
|
2020-07-15 19:32:59 +02:00
|
|
|
<SecondButton
|
2020-01-01 04:31:04 +01:00
|
|
|
icon={{
|
|
|
|
name: 'qrcode',
|
|
|
|
type: 'font-awesome',
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.buttonTextColor,
|
2020-01-01 04:31:04 +01:00
|
|
|
}}
|
2020-08-16 04:43:17 +02:00
|
|
|
onPress={this.openScanner}
|
2020-07-20 15:38:46 +02:00
|
|
|
title={loc.send.psbt_tx_scan}
|
2020-01-01 04:31:04 +01:00
|
|
|
/>
|
|
|
|
<BlueSpacing20 />
|
2020-07-15 19:32:59 +02:00
|
|
|
<SecondButton
|
2020-01-01 04:31:04 +01:00
|
|
|
icon={{
|
|
|
|
name: 'file-import',
|
|
|
|
type: 'material-community',
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.buttonTextColor,
|
2020-01-01 04:31:04 +01:00
|
|
|
}}
|
|
|
|
onPress={this.openSignedTransaction}
|
2020-07-20 15:38:46 +02:00
|
|
|
title={loc.send.psbt_tx_open}
|
2020-01-01 04:31:04 +01:00
|
|
|
/>
|
|
|
|
<BlueSpacing20 />
|
2020-07-15 19:32:59 +02:00
|
|
|
<SecondButton
|
2020-01-01 04:31:04 +01:00
|
|
|
icon={{
|
|
|
|
name: 'share-alternative',
|
|
|
|
type: 'entypo',
|
2020-07-15 19:32:59 +02:00
|
|
|
color: BlueCurrentTheme.colors.buttonTextColor,
|
2020-01-01 04:31:04 +01:00
|
|
|
}}
|
|
|
|
onPress={this.exportPSBT}
|
2020-07-20 15:38:46 +02:00
|
|
|
title={loc.send.psbt_tx_export}
|
2020-01-01 04:31:04 +01:00
|
|
|
/>
|
2019-09-27 16:49:56 +02:00
|
|
|
<BlueSpacing20 />
|
2020-05-24 11:17:26 +02:00
|
|
|
<View style={styles.copyToClipboard}>
|
2020-01-01 04:31:04 +01:00
|
|
|
<BlueCopyToClipboardButton
|
|
|
|
stringToCopy={this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64()}
|
2020-07-20 15:38:46 +02:00
|
|
|
displayText={loc.send.psbt_clipboard}
|
2020-01-01 04:31:04 +01:00
|
|
|
/>
|
2019-09-27 16:49:56 +02:00
|
|
|
</View>
|
|
|
|
</BlueCard>
|
|
|
|
</View>
|
2020-01-01 04:31:04 +01:00
|
|
|
</ScrollView>
|
2019-09-27 16:49:56 +02:00
|
|
|
</SafeBlueArea>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PsbtWithHardwareWallet.propTypes = {
|
|
|
|
navigation: PropTypes.shape({
|
|
|
|
goBack: PropTypes.func,
|
|
|
|
navigate: PropTypes.func,
|
2020-05-27 13:12:17 +02:00
|
|
|
dangerouslyGetParent: PropTypes.func,
|
|
|
|
}),
|
|
|
|
route: PropTypes.shape({
|
|
|
|
params: PropTypes.object,
|
2020-08-16 04:43:17 +02:00
|
|
|
name: PropTypes.string,
|
2019-09-27 16:49:56 +02:00
|
|
|
}),
|
|
|
|
};
|
2020-07-15 19:32:59 +02:00
|
|
|
|
|
|
|
PsbtWithHardwareWallet.navigationOptions = () => ({
|
|
|
|
...BlueNavigationStyle(null, false),
|
|
|
|
title: loc.send.header,
|
|
|
|
});
|