From 9e12222989f0595a8c88f51627dd8a5c663e6600 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Sun, 29 Sep 2019 16:01:27 -0400 Subject: [PATCH 1/4] ADD: Refill with external wallet --- BlueComponents.js | 6 +- MainBottomTabs.js | 28 ++----- screen/lnd/manageFunds.js | 98 ----------------------- screen/receive/details.js | 5 +- screen/send/details.js | 2 +- screen/wallets/transactions.js | 139 ++++++++++++++++++++++++++++++++- 6 files changed, 150 insertions(+), 128 deletions(-) delete mode 100644 screen/lnd/manageFunds.js diff --git a/BlueComponents.js b/BlueComponents.js index 8d637266..e6e01726 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -234,6 +234,10 @@ export class BlueWalletNavigationHeader extends Component { }); } + manageFundsPressed = () => { + this.props.onManageFundsPressed(); + }; + render() { return ( {this.state.wallet.type === LightningCustodianWallet.type && ( - NavigationService.navigate('ManageFunds', { fromWallet: this.state.wallet })}> + ({ - ...BlueNavigationStyle(navigation, true), - title: loc.lnd.title, - headerLeft: null, - }); - - constructor(props) { - super(props); - this.onWalletSelect = this.onWalletSelect.bind(this); - if (!props.navigation.getParam('fromWallet')) throw new Error('Invalid param'); - - this.state = { fromWallet: props.navigation.getParam('fromWallet') }; - } - - async onWalletSelect(wallet) { - this.props.navigation.dismiss(); - /** @type {LightningCustodianWallet} */ - let toAddress = false; - if (this.state.fromWallet.refill_addressess.length > 0) { - toAddress = this.state.fromWallet.refill_addressess[0]; - } else { - try { - await this.state.fromWallet.fetchBtcAddress(); - toAddress = this.state.fromWallet.refill_addressess[0]; - } catch (Err) { - return alert(Err.message); - } - } - - if (wallet) { - setTimeout(() => { - this.props.navigation.navigate('SendDetails', { - memo: loc.lnd.refill_lnd_balance, - fromSecret: wallet.getSecret(), - address: toAddress, - fromWallet: wallet, - }); - }, 100); - } else { - return alert('Internal error'); - } - } - - render() { - return ( - - - - - { - this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect, chainType: Chain.ONCHAIN }); - }} - title={loc.lnd.refill} - /> - { - Linking.openURL('https://zigzag.io/?utm_source=integration&utm_medium=bluewallet&utm_campaign=withdrawLink'); - }} - title={loc.lnd.withdraw} - /> - - - - - ); - } -} - -ManageFunds.propTypes = { - navigation: PropTypes.shape({ - goBack: PropTypes.func, - dismiss: PropTypes.func, - navigate: PropTypes.func, - getParam: PropTypes.func, - state: PropTypes.shape({ - params: PropTypes.shape({ - fromSecret: PropTypes.string, - }), - }), - }), -}; diff --git a/screen/receive/details.js b/screen/receive/details.js index 30f6117a..d7e9e0bf 100644 --- a/screen/receive/details.js +++ b/screen/receive/details.js @@ -70,15 +70,12 @@ export default class ReceiveDetails extends Component { address: address, addressText: address, }); - } else if (wallet.getAddress) { - address = wallet.getAddress(); + } else if (wallet.getAddress && address.trim().length === 0) { this.setState({ address: address, addressText: address, }); } else { - alert('There was a problem obtaining your receive address. Please, try again.'); - this.props.navigation.goBack(); this.setState({ address, addressText: address, diff --git a/screen/send/details.js b/screen/send/details.js index bfc3b419..c5119478 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -37,8 +37,8 @@ import BitcoinBIP70TransactionDecode from '../../bip70/bip70'; import { BitcoinUnit, Chain } from '../../models/bitcoinUnits'; import { HDLegacyP2PKHWallet, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet } from '../../class'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; -const bitcoin = require('bitcoinjs-lib'); import { BitcoinTransaction } from '../../models/bitcoinTransactionInfo'; +const bitcoin = require('bitcoinjs-lib'); const bip21 = require('bip21'); let BigNumber = require('bignumber.js'); const { width } = Dimensions.get('window'); diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 454ed36d..7e787c30 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -4,21 +4,33 @@ import { Chain } from '../../models/bitcoinUnits'; import { Text, Platform, + StyleSheet, View, + Keyboard, ActivityIndicator, InteractionManager, FlatList, RefreshControl, TouchableOpacity, StatusBar, + Linking, + KeyboardAvoidingView, } from 'react-native'; import PropTypes from 'prop-types'; import { NavigationEvents } from 'react-navigation'; -import { BlueSendButtonIcon, BlueReceiveButtonIcon, BlueTransactionListItem, BlueWalletNavigationHeader } from '../../BlueComponents'; +import { + BlueSendButtonIcon, + BlueListItem, + BlueReceiveButtonIcon, + BlueTransactionListItem, + BlueWalletNavigationHeader, +} from '../../BlueComponents'; import { Icon } from 'react-native-elements'; import { LightningCustodianWallet } from '../../class'; import Handoff from 'react-native-handoff'; import { ScrollView } from 'react-native-gesture-handler'; +import Modal from 'react-native-modal'; +import NavigationService from '../../NavigationService'; /** @type {AppStorage} */ let BlueApp = require('../../BlueApp'); let loc = require('../../loc'); @@ -63,6 +75,7 @@ export default class WalletTransactions extends Component { this.state = { showMarketplace: Platform.OS !== 'ios', isLoading: true, + isManageFundsModalVisible: false, showShowFlatListRefreshControl: false, wallet: wallet, dataSource: this.getTransactions(15), @@ -206,7 +219,101 @@ export default class WalletTransactions extends Component { ); }; - + + renderManageFundsModal = () => { + return ( + { + Keyboard.dismiss(); + this.setState({ isManageFundsModalVisible: false }); + }} + > + + + { + const wallets = [...BlueApp.getWallets().filter(item => item.chain === Chain.ONCHAIN && item.allowSend())]; + if (wallets.length === 0) { + alert('In order to proceed, please create a Bitcoin wallet to refill with.'); + } else { + this.setState({ isManageFundsModalVisible: false }); + this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect, chainType: Chain.ONCHAIN }); + } + }} + title={loc.lnd.refill} + /> + { + this.setState({ isManageFundsModalVisible: false }, async () => { + /** @type {LightningCustodianWallet} */ + let toAddress = false; + if (this.state.wallet.refill_addressess.length > 0) { + toAddress = this.state.wallet.refill_addressess[0]; + } else { + try { + await this.state.wallet.fetchBtcAddress(); + toAddress = this.state.wallet.refill_addressess[0]; + } catch (Err) { + return alert(Err.message); + } + } + this.props.navigation.navigate('ReceiveDetails', { + address: toAddress, + secret: this.state.wallet.getSecret(), + }); + }); + }} + title={'Refill with External Wallet'} + /> + + { + this.setState({ isManageFundsModalVisible: false }); + Linking.openURL('https://zigzag.io/?utm_source=integration&utm_medium=bluewallet&utm_campaign=withdrawLink'); + }} + /> + + + + ); + }; + + onWalletSelect = async wallet => { + NavigationService.navigate('WalletTransactions'); + /** @type {LightningCustodianWallet} */ + let toAddress = false; + if (this.state.wallet.refill_addressess.length > 0) { + toAddress = this.state.wallet.refill_addressess[0]; + } else { + try { + await this.state.wallet.fetchBtcAddress(); + toAddress = this.state.wallet.refill_addressess[0]; + } catch (Err) { + return alert(Err.message); + } + } + + if (wallet) { + this.props.navigation.navigate('SendDetails', { + memo: loc.lnd.refill_lnd_balance, + fromSecret: wallet.getSecret(), + address: toAddress, + fromWallet: wallet, + }); + } else { + return alert('Internal error'); + } + }; + async onWillBlur() { StatusBar.setBarStyle('dark-content'); } @@ -245,6 +352,7 @@ export default class WalletTransactions extends Component { this.setState({ wallet }, () => InteractionManager.runAfterInteractions(() => BlueApp.saveToDisk())); }) } + onManageFundsPressed={() => this.setState({ isManageFundsModalVisible: true })} /> {this.state.showMarketplace && ( @@ -343,6 +451,7 @@ export default class WalletTransactions extends Component { renderItem={this.renderItem} contentInset={{ top: 0, left: 0, bottom: 90, right: 0 }} /> + {this.renderManageFundsModal()} Date: Sun, 29 Sep 2019 20:25:22 -0400 Subject: [PATCH 2/4] FIX: Remove unused class --- screen/receive/details.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/screen/receive/details.js b/screen/receive/details.js index d7e9e0bf..f85090fb 100644 --- a/screen/receive/details.js +++ b/screen/receive/details.js @@ -1,4 +1,3 @@ -/* global alert */ import React, { Component } from 'react'; import { View, InteractionManager } from 'react-native'; import QRCode from 'react-native-qrcode-svg'; @@ -70,7 +69,7 @@ export default class ReceiveDetails extends Component { address: address, addressText: address, }); - } else if (wallet.getAddress && address.trim().length === 0) { + } else if (wallet.getAddress) { this.setState({ address: address, addressText: address, From a2271ba62bc862ad58c67fd464b808e86455cd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Rodriguez=20V=C3=A9lez?= Date: Mon, 30 Sep 2019 10:33:05 -0400 Subject: [PATCH 3/4] Update transactions.js --- screen/wallets/transactions.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 7e787c30..c02f524c 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -244,7 +244,7 @@ export default class WalletTransactions extends Component { this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect, chainType: Chain.ONCHAIN }); } }} - title={loc.lnd.refill} + title={'Add funds'} /> { From ddd8ee248777058c54b3c4a31588a5cf9407ffde Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Mon, 30 Sep 2019 18:13:22 -0400 Subject: [PATCH 4/4] FIX: Modify Receive address code --- class/lightning-custodian-wallet.js | 10 +++- screen/receive/details.js | 92 ++++++++++++++++++----------- screen/wallets/transactions.js | 27 +++------ 3 files changed, 73 insertions(+), 56 deletions(-) diff --git a/class/lightning-custodian-wallet.js b/class/lightning-custodian-wallet.js index ab9608bf..fcac7ca7 100644 --- a/class/lightning-custodian-wallet.js +++ b/class/lightning-custodian-wallet.js @@ -44,7 +44,11 @@ export class LightningCustodianWallet extends LegacyWallet { } getAddress() { - return ''; + if (this.refill_addressess.length > 0) { + return this.refill_addressess[0]; + } else { + return undefined; + } } getSecret() { @@ -358,6 +362,10 @@ export class LightningCustodianWallet extends LegacyWallet { } } + async getAddressAsync() { + return this.fetchBtcAddress(); + } + getTransactions() { let txs = []; this.pending_transactions_raw = this.pending_transactions_raw || []; diff --git a/screen/receive/details.js b/screen/receive/details.js index f85090fb..fc8e55ff 100644 --- a/screen/receive/details.js +++ b/screen/receive/details.js @@ -16,6 +16,7 @@ import Privacy from '../../Privacy'; import Share from 'react-native-share'; import { ScrollView } from 'react-native-gesture-handler'; import SystemSetting from 'react-native-system-setting'; +import { Chain } from '../../models/bitcoinUnits'; /** @type {AppStorage} */ let BlueApp = require('../../BlueApp'); let loc = require('../../loc'); @@ -29,62 +30,83 @@ export default class ReceiveDetails extends Component { constructor(props) { super(props); - let address = props.navigation.state.params.address; - let secret = props.navigation.state.params.secret; + let address = props.navigation.state.params.address || ''; + let secret = props.navigation.state.params.secret || ''; this.state = { address: address, secret: secret, - addressText: '', + addressText: address, bip21encoded: undefined, }; } async componentDidMount() { Privacy.enableBlur(); + await SystemSetting.saveBrightness(); + await SystemSetting.setAppBrightness(1.0); console.log('receive/details - componentDidMount'); /** @type {AbstractWallet} */ - let wallet; let address = this.state.address; - for (let w of BlueApp.getWallets()) { - if ((address && w.getAddress() === this.state.address) || w.getSecret() === this.state.secret) { - // found our wallet - wallet = w; + + if (address.trim().length === 0) { + let wallet; + for (let w of BlueApp.getWallets()) { + if ((address && w.getAddress() === this.state.address) || w.getSecret() === this.state.secret) { + // found our wallet + wallet = w; + } } - } - if (wallet) { - if (wallet.getAddressAsync) { - try { - address = await Promise.race([wallet.getAddressAsync(), BlueApp.sleep(1000)]); - } catch (_) {} - if (!address) { - // either sleep expired or getAddressAsync threw an exception - console.warn('either sleep expired or getAddressAsync threw an exception'); - address = wallet._getExternalAddressByIndex(wallet.next_free_address_index); + if (wallet) { + if (wallet.getAddressAsync) { + if (wallet.chain === Chain.ONCHAIN) { + try { + address = await Promise.race([wallet.getAddressAsync(), BlueApp.sleep(1000)]); + } catch (_) {} + if (!address) { + // either sleep expired or getAddressAsync threw an exception + console.warn('either sleep expired or getAddressAsync threw an exception'); + address = wallet._getExternalAddressByIndex(wallet.next_free_address_index); + } else { + BlueApp.saveToDisk(); // caching whatever getAddressAsync() generated internally + } + this.setState({ + address: address, + addressText: address, + }); + } else if (wallet.chain === Chain.OFFCHAIN) { + try { + await Promise.race([wallet.getAddressAsync(), BlueApp.sleep(1000)]); + address = wallet.getAddress(); + } catch (_) {} + if (!address) { + // either sleep expired or getAddressAsync threw an exception + console.warn('either sleep expired or getAddressAsync threw an exception'); + address = wallet.getAddress(); + } else { + BlueApp.saveToDisk(); // caching whatever getAddressAsync() generated internally + } + } + this.setState({ + address: address, + addressText: address, + }); + } else if (wallet.getAddress) { + this.setState({ + address: address, + addressText: address, + }); } else { - BlueApp.saveToDisk(); // caching whatever getAddressAsync() generated internally + this.setState({ + address, + addressText: address, + }); } - this.setState({ - address: address, - addressText: address, - }); - } else if (wallet.getAddress) { - this.setState({ - address: address, - addressText: address, - }); - } else { - this.setState({ - address, - addressText: address, - }); } } InteractionManager.runAfterInteractions(async () => { - await SystemSetting.saveBrightness(); - await SystemSetting.setAppBrightness(1.0); const bip21encoded = bip21.encode(this.state.address); this.setState({ bip21encoded }); }); diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index c02f524c..04321624 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -241,39 +241,26 @@ export default class WalletTransactions extends Component { alert('In order to proceed, please create a Bitcoin wallet to refill with.'); } else { this.setState({ isManageFundsModalVisible: false }); - this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect, chainType: Chain.ONCHAIN }); + this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect, chainType: Chain.ONCHAIN }); } }} - title={'Add funds'} + title={loc.lnd.refill} /> { - this.setState({ isManageFundsModalVisible: false }, async () => { - /** @type {LightningCustodianWallet} */ - let toAddress = false; - if (this.state.wallet.refill_addressess.length > 0) { - toAddress = this.state.wallet.refill_addressess[0]; - } else { - try { - await this.state.wallet.fetchBtcAddress(); - toAddress = this.state.wallet.refill_addressess[0]; - } catch (Err) { - return alert(Err.message); - } - } + this.setState({ isManageFundsModalVisible: false }, () => this.props.navigation.navigate('ReceiveDetails', { - address: toAddress, secret: this.state.wallet.getSecret(), - }); - }); + }), + ); }} - title={'Add funds using external wallet'} + title={'Refill with External Wallet'} /> {