/* global alert */ import React, { Component } from 'react'; import { ActivityIndicator, FlatList, TouchableOpacity, StyleSheet, View } from 'react-native'; import { Text } from 'react-native-elements'; import { BlueButton, BlueText, SafeBlueArea, BlueCard, BlueSpacing40, BlueNavigationStyle } from '../../BlueComponents'; import { BitcoinUnit } from '../../models/bitcoinUnits'; import PropTypes from 'prop-types'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import Biometric from '../../class/biometrics'; import { HDLegacyElectrumSeedP2PKHWallet, HDLegacyP2PKHWallet, HDSegwitBech32Wallet, HDSegwitP2SHWallet, HDLegacyBreadwalletWallet, LegacyWallet, SegwitP2SHWallet, SegwitBech32Wallet, } from '../../class'; let loc = require('../../loc'); let EV = require('../../events'); let currency = require('../../currency'); let BlueElectrum = require('../../BlueElectrum'); let Bignumber = require('bignumber.js'); /** @type {AppStorage} */ const BlueApp = require('../../BlueApp'); export default class Confirm extends Component { static navigationOptions = () => ({ ...BlueNavigationStyle(null, false), title: loc.send.confirm.header, }); constructor(props) { super(props); this.state = { isLoading: false, fee: props.navigation.getParam('fee'), feeSatoshi: new Bignumber(props.navigation.getParam('fee')).multipliedBy(100000000).toNumber(), memo: props.navigation.getParam('memo'), recipients: props.navigation.getParam('recipients'), size: Math.round(props.navigation.getParam('tx').length / 2), tx: props.navigation.getParam('tx'), satoshiPerByte: props.navigation.getParam('satoshiPerByte'), fromWallet: props.navigation.getParam('fromWallet'), }; } async componentDidMount() { console.log('send/confirm - componentDidMount'); console.log('address = ', this.state.recipients); this.isBiometricUseCapableAndEnabled = await Biometric.isBiometricUseCapableAndEnabled(); } broadcast() { this.setState({ isLoading: true }, async () => { try { await BlueElectrum.ping(); await BlueElectrum.waitTillConnected(); if (this.isBiometricUseCapableAndEnabled) { if (!(await Biometric.unlockWithBiometrics())) { this.setState({ isLoading: false }); return; } } let result = await this.state.fromWallet.broadcastTx(this.state.tx); if (result && result.code) { if (result.code === 1) { const message = result.message.split('\n'); throw new Error(`${message[0]}: ${message[2]}`); } } else { console.log('broadcast result = ', result); EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs let amount = 0; const recipients = this.state.recipients; if (recipients[0].amount === BitcoinUnit.MAX || !recipients[0].amount) { amount = this.state.fromWallet.getBalance() - this.state.feeSatoshi; } else { for (const recipient of recipients) { amount += recipient.amount ? +recipient.amount : recipient.value; } } // wallets that support new createTransaction() instead of deprecated createTx() if ( [ HDSegwitBech32Wallet.type, HDSegwitP2SHWallet.type, HDLegacyP2PKHWallet.type, HDLegacyBreadwalletWallet.type, HDLegacyElectrumSeedP2PKHWallet.type, LegacyWallet.type, SegwitP2SHWallet.type, SegwitBech32Wallet.type, ].includes(this.state.fromWallet.type) ) { amount = loc.formatBalanceWithoutSuffix(amount, BitcoinUnit.BTC, false); } this.props.navigation.navigate('Success', { fee: Number(this.state.fee), amount, dismissModal: () => this.props.navigation.dismiss(), }); this.setState({ isLoading: false }); } } catch (error) { ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); this.setState({ isLoading: false }); alert(error.message); } }); } _renderItem = ({ index, item }) => { return ( <> {!item.amount || item.amount === BitcoinUnit.MAX ? currency.satoshiToBTC(this.state.fromWallet.getBalance() - this.state.feeSatoshi) : item.amount || currency.satoshiToBTC(item.value)} {' ' + BitcoinUnit.BTC} {loc.send.create.to} {item.address} {this.state.recipients.length > 1 && ( {index + 1} of {this.state.recipients.length} )} ); }; renderSeparator = () => { return ; }; render() { return ( 1} extraData={this.state.recipients} data={this.state.recipients} renderItem={this._renderItem} keyExtractor={(_item, index) => `${index}`} ItemSeparatorComponent={this.renderSeparator} style={{ maxHeight: '55%' }} /> {loc.send.create.fee}: {loc.formatBalance(this.state.feeSatoshi, BitcoinUnit.BTC)} ( {currency.satoshiToLocalCurrency(this.state.feeSatoshi)}) {this.state.isLoading ? ( ) : ( this.broadcast()} title={loc.send.confirm.sendNow} /> )} { if (this.isBiometricUseCapableAndEnabled) { if (!(await Biometric.unlockWithBiometrics())) { return; } } this.props.navigation.navigate('CreateTransaction', { fee: this.state.fee, recipients: this.state.recipients, memo: this.state.memo, tx: this.state.tx, satoshiPerByte: this.state.satoshiPerByte, wallet: this.state.fromWallet, feeSatoshi: this.state.feeSatoshi, }); }} > {loc.transactions.details.transaction_details} ); } } const styles = StyleSheet.create({ transactionDetailsTitle: { color: '#0c2550', fontWeight: '500', fontSize: 17, marginBottom: 2, }, transactionDetailsSubtitle: { color: '#9aa0aa', fontWeight: '500', fontSize: 15, marginBottom: 20, }, }); Confirm.propTypes = { navigation: PropTypes.shape({ goBack: PropTypes.func, getParam: PropTypes.func, navigate: PropTypes.func, dismiss: PropTypes.func, state: PropTypes.shape({ params: PropTypes.shape({ amount: PropTypes.string, fee: PropTypes.number, address: PropTypes.string, memo: PropTypes.string, fromWallet: PropTypes.shape({ fromAddress: PropTypes.string, fromSecret: PropTypes.string, }), }), }), }), };