/* global alert */ import React, { Component } from 'react'; import { ActivityIndicator, TouchableOpacity, View, Dimensions, Image, TextInput, Clipboard, Linking } from 'react-native'; import QRCode from 'react-native-qrcode-svg'; import { Icon, Text } from 'react-native-elements'; import { BlueButton, BlueText, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueSpacing20, BlueCopyToClipboardButton, } from '../../BlueComponents'; import PropTypes from 'prop-types'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import { RNCamera } from 'react-native-camera'; let loc = require('../../loc'); let EV = require('../../events'); let BlueElectrum = require('../../BlueElectrum'); /** @type {AppStorage} */ const BlueApp = require('../../BlueApp'); const bitcoin = require('bitcoinjs-lib'); const { height, width } = Dimensions.get('window'); export default class PsbtWithHardwareWallet extends Component { static navigationOptions = () => ({ ...BlueNavigationStyle(null, false), title: loc.send.header, }); cameraRef = null; onBarCodeRead = ret => { if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.pausePreview(); this.setState({ renderScanner: false }, () => { console.log(ret.data); try { let Tx = this.state.fromWallet.combinePsbt(this.state.psbt.toBase64(), ret.data); this.setState({ txhex: Tx.toHex() }); } catch (Err) { alert(Err); } }); }; constructor(props) { super(props); this.state = { isLoading: false, renderScanner: false, qrCodeHeight: height > width ? width - 40 : width / 2, memo: props.navigation.getParam('memo'), psbt: props.navigation.getParam('psbt'), fromWallet: props.navigation.getParam('fromWallet'), }; } async componentDidMount() { console.log('send/psbtWithHardwareWallet - componentDidMount'); } broadcast = () => { this.setState({ isLoading: true }, async () => { try { await BlueElectrum.ping(); await BlueElectrum.waitTillConnected(); let result = await this.state.fromWallet.broadcastTx(this.state.txhex); if (result) { console.log('broadcast result = ', result); EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs this.setState({ success: true, isLoading: false }); if (this.state.memo) { let txDecoded = bitcoin.Transaction.fromHex(this.state.txhex); const txid = txDecoded.getId(); BlueApp.tx_metadata[txid] = { memo: this.state.memo }; } } else { ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); this.setState({ isLoading: false }); alert('Broadcast failed'); } } catch (error) { ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); this.setState({ isLoading: false }); alert(error.message); } }); }; _renderScanner() { return ( (this.cameraRef = ref)} style={{ flex: 1, justifyContent: 'space-between' }} onBarCodeRead={this.onBarCodeRead} barCodeTypes={[RNCamera.Constants.BarCodeType.qr]} /> this.setState({ renderScanner: false })} > ); } _renderSuccess() { return ( ); } _renderBroadcastHex() { return ( {loc.send.create.this_is_hex} Clipboard.setString(this.state.txhex)}> Copy and broadcast later Linking.openURL('https://coinb.in/?verify=' + this.state.txhex)}> Verify on coinb.in ); } render() { if (this.state.isLoading) { return ( ); } if (this.state.success) return this._renderSuccess(); if (this.state.renderScanner) return this._renderScanner(); if (this.state.txhex) return this._renderBroadcastHex(); return ( This is partially signed bitcoin transaction (PSBT). Please finish signing it with your hardware wallet. this.setState({ renderScanner: true })} title={'Scan signed transaction'} /> ); } } PsbtWithHardwareWallet.propTypes = { navigation: PropTypes.shape({ goBack: PropTypes.func, getParam: PropTypes.func, navigate: PropTypes.func, dismiss: PropTypes.func, state: PropTypes.shape({ params: PropTypes.shape({ memo: PropTypes.string, fromWallet: PropTypes.shape({ fromAddress: PropTypes.string, fromSecret: PropTypes.string, }), }), }), }), };