mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 09:50:15 +01:00
ADD: broadcast txhex screen
This commit is contained in:
parent
433b189cb5
commit
f7028431ce
@ -2340,3 +2340,22 @@ const styles = StyleSheet.create({
|
||||
marginRight: 16,
|
||||
},
|
||||
});
|
||||
|
||||
export function BlueBigCheckmark({ style }) {
|
||||
const defaultStyles = {
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 0,
|
||||
marginBottom: 0,
|
||||
};
|
||||
const mergedStyles = { ...defaultStyles, ...style };
|
||||
return (
|
||||
<View style={mergedStyles}>
|
||||
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ import sendCreate from './screen/send/create';
|
||||
import Confirm from './screen/send/confirm';
|
||||
import PsbtWithHardwareWallet from './screen/send/psbtWithHardwareWallet';
|
||||
import Success from './screen/send/success';
|
||||
import Broadcast from './screen/send/broadcast';
|
||||
|
||||
import ScanLndInvoice from './screen/lnd/scanLndInvoice';
|
||||
import LappBrowser from './screen/lnd/browser';
|
||||
@ -199,6 +200,9 @@ const CreateTransactionStackNavigator = createStackNavigator({
|
||||
headerRight: null,
|
||||
},
|
||||
},
|
||||
Broadcast: {
|
||||
screen: Broadcast,
|
||||
},
|
||||
});
|
||||
|
||||
const LNDCreateInvoiceStackNavigator = createStackNavigator({
|
||||
@ -325,12 +329,17 @@ const MainBottomTabs = createStackNavigator(
|
||||
},
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
ReceiveDetails: {
|
||||
screen: receiveDetails,
|
||||
},
|
||||
|
||||
Broadcast: {
|
||||
screen: Broadcast,
|
||||
navigationOptions: () => ({
|
||||
title: 'Broadcast tx',
|
||||
}),
|
||||
},
|
||||
|
||||
//
|
||||
|
||||
// LND:
|
||||
|
@ -988,19 +988,6 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
return txs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast txhex. Can throw an exception if failed
|
||||
*
|
||||
* @param {String} txhex
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async broadcastTx(txhex) {
|
||||
let broadcast = await BlueElectrum.broadcastV2(txhex);
|
||||
console.log({ broadcast });
|
||||
if (broadcast.indexOf('successfully') !== -1) return true;
|
||||
return broadcast.length === 64; // this means return string is txid (precise length), so it was broadcasted ok
|
||||
}
|
||||
|
||||
/**
|
||||
* Probes zero address in external hierarchy for transactions, if there are any returns TRUE.
|
||||
* Zero address is a pretty good indicator, since its a first one to fund the wallet. How can you use the wallet and
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { AbstractWallet } from './abstract-wallet';
|
||||
import { HDSegwitBech32Wallet } from './';
|
||||
import { NativeModules } from 'react-native';
|
||||
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const { RNRandomBytes } = NativeModules;
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
@ -245,13 +246,17 @@ export class LegacyWallet extends AbstractWallet {
|
||||
return hd.getTransactions.apply(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast txhex. Can throw an exception if failed
|
||||
*
|
||||
* @param {String} txhex
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async broadcastTx(txhex) {
|
||||
try {
|
||||
const broadcast = await BlueElectrum.broadcast(txhex);
|
||||
return broadcast;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
let broadcast = await BlueElectrum.broadcastV2(txhex);
|
||||
console.log({ broadcast });
|
||||
if (broadcast.indexOf('successfully') !== -1) return true;
|
||||
return broadcast.length === 64; // this means return string is txid (precise length), so it was broadcasted ok
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
BlueCopyTextToClipboard,
|
||||
BlueNavigationStyle,
|
||||
BlueSpacing20,
|
||||
BlueBigCheckmark
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
@ -187,20 +188,7 @@ export default class LNDViewInvoice extends Component {
|
||||
</View>
|
||||
|
||||
<View style={{ flex: 3, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: -100,
|
||||
marginBottom: 16,
|
||||
}}
|
||||
>
|
||||
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
<BlueBigCheckmark style={{ marginTop: -100, marginBottom: 16 }} />
|
||||
<BlueText>{loc.lndViewInvoice.has_been_paid}</BlueText>
|
||||
</View>
|
||||
<View style={{ flex: 1, justifyContent: 'flex-end', marginBottom: 24, alignItems: 'center' }}>
|
||||
|
162
screen/send/broadcast.js
Normal file
162
screen/send/broadcast.js
Normal file
@ -0,0 +1,162 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ActivityIndicator, Linking, StyleSheet, View, KeyboardAvoidingView, Platform, Text, TextInput } from 'react-native';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
import { HDSegwitBech32Wallet } from '../../class';
|
||||
import {
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueButton,
|
||||
BlueSpacing10,
|
||||
BlueSpacing20,
|
||||
BlueFormLabel,
|
||||
BlueTextCentered,
|
||||
BlueBigCheckmark,
|
||||
} from '../../BlueComponents';
|
||||
import BlueElectrum from '../../BlueElectrum';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
|
||||
const BROADCAST_RESULT = Object.freeze({
|
||||
none: 'Input transaction hash',
|
||||
pending: 'pending',
|
||||
success: 'success',
|
||||
error: 'error',
|
||||
});
|
||||
|
||||
export default function Broadcast() {
|
||||
const [tx, setTx] = useState('');
|
||||
const [txHex, setTxHex] = useState('');
|
||||
const [broadcastResult, setBroadcastResult] = useState(BROADCAST_RESULT.none);
|
||||
const handleUpdateTxHex = nextValue => setTxHex(nextValue.trim());
|
||||
const handleBroadcast = async () => {
|
||||
setBroadcastResult(BROADCAST_RESULT.pending);
|
||||
try {
|
||||
await BlueElectrum.ping();
|
||||
await BlueElectrum.waitTillConnected();
|
||||
const walletObj = new HDSegwitBech32Wallet();
|
||||
const result = await walletObj.broadcastTx(txHex);
|
||||
if (result) {
|
||||
let tx = bitcoin.Transaction.fromHex(txHex);
|
||||
const txid = tx.getId();
|
||||
setTx(txid);
|
||||
setBroadcastResult(BROADCAST_RESULT.success);
|
||||
} else {
|
||||
setBroadcastResult(BROADCAST_RESULT.error);
|
||||
}
|
||||
} catch (error) {
|
||||
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
|
||||
setBroadcastResult(BROADCAST_RESULT.error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={styles.blueArea}>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null} keyboardShouldPersistTaps="handled">
|
||||
<View style={styles.wrapper}>
|
||||
{BROADCAST_RESULT.success !== broadcastResult && (
|
||||
<BlueCard style={styles.mainCard}>
|
||||
<View style={styles.topFormRow}>
|
||||
<BlueFormLabel>{broadcastResult}</BlueFormLabel>
|
||||
{BROADCAST_RESULT.pending === broadcastResult && <ActivityIndicator size="small" />}
|
||||
</View>
|
||||
<TextInput
|
||||
style={{
|
||||
flex: 1,
|
||||
borderColor: '#ebebeb',
|
||||
backgroundColor: '#d2f8d6',
|
||||
borderRadius: 4,
|
||||
marginTop: 20,
|
||||
color: '#37c0a1',
|
||||
fontWeight: '500',
|
||||
fontSize: 14,
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 16,
|
||||
paddingTop: 16,
|
||||
}}
|
||||
maxHeight={100}
|
||||
minHeight={100}
|
||||
maxWidth={'100%'}
|
||||
minWidth={'100%'}
|
||||
multiline
|
||||
editable
|
||||
value={txHex}
|
||||
onChangeText={handleUpdateTxHex}
|
||||
/>
|
||||
|
||||
<BlueSpacing10 />
|
||||
<BlueButton title="BROADCAST" onPress={handleBroadcast} disabled={broadcastResult === BROADCAST_RESULT.pending} />
|
||||
</BlueCard>
|
||||
)}
|
||||
{BROADCAST_RESULT.success === broadcastResult && <SuccessScreen tx={tx} />}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
marginTop: 16,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
blueArea: {
|
||||
flex: 1,
|
||||
paddingTop: 19,
|
||||
},
|
||||
broadcastResultWrapper: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
},
|
||||
link: {
|
||||
color: 'blue',
|
||||
},
|
||||
mainCard: {
|
||||
padding: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
},
|
||||
topFormRow: {
|
||||
flex: 0.1,
|
||||
flexBasis: 0.1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingBottom: 10,
|
||||
paddingTop: 0,
|
||||
paddingRight: 100,
|
||||
height: 30,
|
||||
maxHeight: 30,
|
||||
},
|
||||
});
|
||||
|
||||
function SuccessScreen({ tx }) {
|
||||
if (!tx) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<BlueCard>
|
||||
<View style={styles.broadcastResultWrapper}>
|
||||
<BlueBigCheckmark />
|
||||
<BlueSpacing20 />
|
||||
<BlueTextCentered>Success! You transaction has been broadcasted!</BlueTextCentered>
|
||||
<BlueSpacing10 />
|
||||
<Text style={styles.link} onPress={() => Linking.openURL(`https://blockstream.info/tx/${tx}`)}>
|
||||
Open link in explorer
|
||||
</Text>
|
||||
</View>
|
||||
</BlueCard>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
SuccessScreen.propTypes = {
|
||||
tx: PropTypes.string.isRequired,
|
||||
};
|
@ -67,13 +67,9 @@ export default class Confirm extends Component {
|
||||
}
|
||||
|
||||
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]}`);
|
||||
}
|
||||
if (!result) {
|
||||
throw new Error(`Broadcast failed`);
|
||||
} 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;
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
PermissionsAndroid,
|
||||
} from 'react-native';
|
||||
import QRCode from 'react-native-qrcode-svg';
|
||||
import { Icon, Text } from 'react-native-elements';
|
||||
import { Text } from 'react-native-elements';
|
||||
import {
|
||||
BlueButton,
|
||||
BlueText,
|
||||
@ -23,6 +23,7 @@ import {
|
||||
BlueNavigationStyle,
|
||||
BlueSpacing20,
|
||||
BlueCopyToClipboardButton,
|
||||
BlueBigCheckmark,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import Share from 'react-native-share';
|
||||
@ -121,7 +122,6 @@ export default class PsbtWithHardwareWallet extends Component {
|
||||
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) {
|
||||
@ -180,20 +180,7 @@ export default class PsbtWithHardwareWallet extends Component {
|
||||
_renderSuccess() {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 143,
|
||||
marginBottom: 53,
|
||||
}}
|
||||
>
|
||||
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
<BlueBigCheckmark style={{ marginTop: 143, marginBottom: 53 }} />
|
||||
<BlueCard>
|
||||
<BlueButton onPress={this.props.navigation.dismiss} title={loc.send.success.done} />
|
||||
</BlueCard>
|
||||
|
@ -10,10 +10,11 @@ import {
|
||||
BlueText,
|
||||
BlueSpacing,
|
||||
BlueNavigationStyle,
|
||||
BlueBigCheckmark,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class';
|
||||
import { Icon, Text } from 'react-native-elements';
|
||||
import { Text } from 'react-native-elements';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
/** @type {AppStorage} */
|
||||
let EV = require('../../events');
|
||||
@ -50,7 +51,6 @@ export default class CPFP extends Component {
|
||||
await BlueElectrum.waitTillConnected();
|
||||
let result = await this.state.wallet.broadcastTx(this.state.txhex);
|
||||
if (result) {
|
||||
console.log('broadcast result = ', result);
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
|
||||
this.setState({ stage: 3, isLoading: false });
|
||||
this.onSuccessBroadcast();
|
||||
@ -192,20 +192,7 @@ export default class CPFP extends Component {
|
||||
<BlueCard style={{ alignItems: 'center', flex: 1 }}>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 76, paddingBottom: 16 }} />
|
||||
</BlueCard>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 43,
|
||||
marginBottom: 53,
|
||||
}}
|
||||
>
|
||||
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
<BlueBigCheckmark style={{ marginTop: 43, marginBottom: 53 }} />
|
||||
<BlueCard>
|
||||
<BlueButton
|
||||
onPress={() => {
|
||||
|
@ -260,7 +260,8 @@ export default class WalletDetails extends Component {
|
||||
/>
|
||||
)}
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueButton onPress={() => this.props.navigation.navigate('Broadcast')} title="Broadcast transaction" />
|
||||
<BlueSpacing20 />
|
||||
<TouchableOpacity
|
||||
style={{ alignItems: 'center' }}
|
||||
onPress={() => {
|
||||
|
Loading…
Reference in New Issue
Block a user