From d40ac66bf137ca837fc11962818d68fe83f1dd85 Mon Sep 17 00:00:00 2001 From: Overtorment Date: Sun, 4 Aug 2019 20:33:15 +0100 Subject: [PATCH 01/10] ADD: send MAX (for BIP84 & BIP49) --- BlueComponents.js | 7 +++++++ class/abstract-wallet.js | 4 ++++ class/hd-segwit-bech32-wallet.js | 4 ++++ class/hd-segwit-p2sh-wallet.js | 22 ++++++++++++++++++++++ models/bitcoinUnits.js | 1 + screen/send/details.js | 22 ++++++++++++++++++++++ tests/integration/HDWallet.test.js | 30 ++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+) diff --git a/BlueComponents.js b/BlueComponents.js index ca34144d5..ae6ee094f 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -1923,6 +1923,7 @@ export class BlueBitcoinAmount extends Component { } else { localCurrency = loc.formatBalanceWithoutSuffix(amount.toString(), BitcoinUnit.LOCAL_CURRENCY, false); } + if (amount === BitcoinUnit.MAX) localCurrency = ''; // we dont want to display NaN return ( this.textInput.focus()}> @@ -1939,6 +1940,12 @@ export class BlueBitcoinAmount extends Component { } this.props.onChangeText(text); }} + onBlur={() => { + if (this.props.onBlur) this.props.onBlur(); + }} + onFocus={() => { + if (this.props.onFocus) this.props.onFocus(); + }} placeholder="0" maxLength={10} ref={textInput => (this.textInput = textInput)} diff --git a/class/abstract-wallet.js b/class/abstract-wallet.js index 2583af91c..adb9a15c0 100644 --- a/class/abstract-wallet.js +++ b/class/abstract-wallet.js @@ -68,6 +68,10 @@ export class AbstractWallet { return true; } + allowSendMax(): boolean { + return false; + } + allowRBF() { return false; } diff --git a/class/hd-segwit-bech32-wallet.js b/class/hd-segwit-bech32-wallet.js index b41596cd8..a124d04b9 100644 --- a/class/hd-segwit-bech32-wallet.js +++ b/class/hd-segwit-bech32-wallet.js @@ -36,6 +36,10 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet { return true; } + allowSendMax(): boolean { + return true; + } + /** * @inheritDoc */ diff --git a/class/hd-segwit-p2sh-wallet.js b/class/hd-segwit-p2sh-wallet.js index 1e0a9c29d..7a225fbc6 100644 --- a/class/hd-segwit-p2sh-wallet.js +++ b/class/hd-segwit-p2sh-wallet.js @@ -5,6 +5,7 @@ import bip39 from 'bip39'; import BigNumber from 'bignumber.js'; import b58 from 'bs58check'; import signer from '../models/signer'; +import { BitcoinUnit } from '../models/bitcoinUnits'; const bitcoin = require('bitcoinjs-lib'); const bitcoin5 = require('bitcoinjs5'); const HDNode = require('bip32'); @@ -49,6 +50,10 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet { return true; } + allowSendMax(): boolean { + return true; + } + async generate() { let that = this; return new Promise(function(resolve) { @@ -255,12 +260,29 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet { } } + /** + * + * @param utxos + * @param amount Either float (BTC) or string 'MAX' (BitcoinUnit.MAX) to send all + * @param fee + * @param address + * @returns {string} + */ createTx(utxos, amount, fee, address) { for (let utxo of utxos) { utxo.wif = this._getWifForAddress(utxo.address); } let amountPlusFee = parseFloat(new BigNumber(amount).plus(fee).toString(10)); + + if (amount === BitcoinUnit.MAX) { + amountPlusFee = new BigNumber(0); + for (let utxo of utxos) { + amountPlusFee = amountPlusFee.plus(utxo.amount); + } + amountPlusFee = amountPlusFee.dividedBy(100000000).toString(10); + } + return signer.createHDSegwitTransaction( utxos, address, diff --git a/models/bitcoinUnits.js b/models/bitcoinUnits.js index 2e96e2189..d436f27d4 100644 --- a/models/bitcoinUnits.js +++ b/models/bitcoinUnits.js @@ -2,6 +2,7 @@ export const BitcoinUnit = Object.freeze({ BTC: 'BTC', SATS: 'sats', LOCAL_CURRENCY: 'local_currency', + MAX: 'MAX', }); export const Chain = Object.freeze({ diff --git a/screen/send/details.js b/screen/send/details.js index 4ce1597ae..ee5547f41 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -22,6 +22,7 @@ import { BlueAddressInput, BlueDismissKeyboardInputAccessory, BlueLoading, + BlueButtonLink, } from '../../BlueComponents'; import Slider from '@react-native-community/slider'; import PropTypes from 'prop-types'; @@ -72,6 +73,7 @@ export default class SendDetails extends Component { } this.state = { isLoading: true, + showSendMax: false, isFeeSelectionModalVisible: false, fromAddress, fromWallet, @@ -466,6 +468,9 @@ export default class SendDetails extends Component { let targets = []; targets.push({ address: this.state.address, value: satoshis }); + if (this.state.amount === BitcoinUnit.MAX) { + targets = [{ address: this.state.address }]; + } let { tx, fee } = wallet.createTransaction(wallet.getUtxo(), targets, requestedSatPerByte, changeAddress); @@ -629,8 +634,25 @@ export default class SendDetails extends Component { isLoading={this.state.isLoading} amount={this.state.amount.toString()} onChangeText={text => this.setState({ amount: text })} + onBlur={() => { + this.setState({ showSendMax: false }); + }} + onFocus={() => { + this.setState({ showSendMax: true }); + }} inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID} /> + {this.state.showSendMax && this.state.fromWallet.allowSendMax() && ( + + { + console.log('state was set'); + this.setState({ amount: 'MAX' }); + }} + /> + + )} { if (!this.processBIP70Invoice(text)) { diff --git a/tests/integration/HDWallet.test.js b/tests/integration/HDWallet.test.js index ae8ba1b83..939c22910 100644 --- a/tests/integration/HDWallet.test.js +++ b/tests/integration/HDWallet.test.js @@ -1,5 +1,6 @@ /* global it, jasmine, afterAll, beforeAll */ import { SegwitP2SHWallet, SegwitBech32Wallet, HDSegwitP2SHWallet, HDLegacyBreadwalletWallet, HDLegacyP2PKHWallet } from '../../class'; +import {BitcoinUnit} from "../../models/bitcoinUnits"; global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment let assert = require('assert'); let bitcoin = require('bitcoinjs-lib'); @@ -177,6 +178,35 @@ it('HD (BIP49) can create TX', async () => { chunksIn = bitcoin.script.decompile(tx.outs[0].script); toAddress = bitcoin.address.fromOutputScript(chunksIn); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); + + // testing sendMAX + hd.utxo = [ + { + txid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + vout: 0, + amount: 26000, + address: '3GgPyzKfWXiaXMbJ9LeEVGetvEXdrX9Ecj', + wif: 'L3fg5Jb6tJDVMvoG2boP4u3CxjX1Er3e7Z4zDALQdGgVLLE8zVUr', + }, + { + txid: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + vout: 0, + amount: 26000, + address: '3GgPyzKfWXiaXMbJ9LeEVGetvEXdrX9Ecj', + wif: 'L3fg5Jb6tJDVMvoG2boP4u3CxjX1Er3e7Z4zDALQdGgVLLE8zVUr', + }, + { + txid: 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + vout: 0, + amount: 26000, + address: '3GgPyzKfWXiaXMbJ9LeEVGetvEXdrX9Ecj', + wif: 'L3fg5Jb6tJDVMvoG2boP4u3CxjX1Er3e7Z4zDALQdGgVLLE8zVUr', + }, + ]; + txhex = hd.createTx(hd.utxo, BitcoinUnit.MAX, 0.00003, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK'); + tx = bitcoin.Transaction.fromHex(txhex); + assert.strictEqual(tx.outs.length, 1); + assert.strictEqual(tx.outs[0].value, 75000); }); it('Segwit HD (BIP49) can fetch UTXO', async function() { From f3e35e7bbaec5d83c371a471df95e51149ccca13 Mon Sep 17 00:00:00 2001 From: Overtorment Date: Sun, 4 Aug 2019 20:34:17 +0100 Subject: [PATCH 02/10] REF --- loc/cs_CZ.js | 2 +- loc/da_DK.js | 2 +- loc/de_DE.js | 2 +- loc/el.js | 2 +- loc/en.js | 2 +- loc/es.js | 2 +- loc/fi_FI.js | 2 +- loc/fr_FR.js | 2 +- loc/hr_HR.js | 2 +- loc/hu_HU.js | 2 +- loc/id_ID.js | 2 +- loc/it.js | 2 +- loc/jp_JP.js | 2 +- loc/nb_NO.js | 2 +- loc/nl_NL.js | 2 +- loc/pt_BR.js | 2 +- loc/pt_PT.js | 2 +- loc/ru.js | 2 +- loc/sv_SE.js | 2 +- loc/th_TH.js | 2 +- loc/tr_TR.js | 2 +- loc/ua.js | 2 +- loc/zh_cn.js | 2 +- package.json | 2 +- react-native.config.js | 2 +- screen/lnd/lndCreateInvoice.js | 40 ++++++++++++++++++++-------------- screen/wallets/transactions.js | 20 +---------------- 27 files changed, 50 insertions(+), 60 deletions(-) diff --git a/loc/cs_CZ.js b/loc/cs_CZ.js index 0115ecd87..55380caea 100644 --- a/loc/cs_CZ.js +++ b/loc/cs_CZ.js @@ -165,7 +165,7 @@ module.exports = { create: 'Create', setAmount: 'Přijmout částku...', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Koupit Bitcoin', diff --git a/loc/da_DK.js b/loc/da_DK.js index 7d7ccfa5c..efd91e478 100644 --- a/loc/da_DK.js +++ b/loc/da_DK.js @@ -165,7 +165,7 @@ module.exports = { create: 'Create', setAmount: 'Modtag med beløb', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Køb Bitcoin', diff --git a/loc/de_DE.js b/loc/de_DE.js index dbd9b7d03..058b8d7fb 100644 --- a/loc/de_DE.js +++ b/loc/de_DE.js @@ -167,7 +167,7 @@ module.exports = { create: 'Create', setAmount: 'Zu erhaltender Betrag', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Kaufe Bitcoin', diff --git a/loc/el.js b/loc/el.js index a1971e12c..a93c1f1a5 100644 --- a/loc/el.js +++ b/loc/el.js @@ -168,7 +168,7 @@ module.exports = { create: 'Δημιούργησε', setAmount: 'Λάβε με ποσό', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Αγόρασε Bitcoin', diff --git a/loc/en.js b/loc/en.js index 7cd40b4ab..ebeb2ba8a 100644 --- a/loc/en.js +++ b/loc/en.js @@ -166,7 +166,7 @@ module.exports = { create: 'Create', setAmount: 'Receive with amount', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Buy Bitcoin', diff --git a/loc/es.js b/loc/es.js index b077295d1..51f3eb657 100644 --- a/loc/es.js +++ b/loc/es.js @@ -167,7 +167,7 @@ module.exports = { create: 'Create', setAmount: 'Receive with amount', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Buy Bitcoin', diff --git a/loc/fi_FI.js b/loc/fi_FI.js index f24d48888..2d500a998 100644 --- a/loc/fi_FI.js +++ b/loc/fi_FI.js @@ -168,7 +168,7 @@ module.exports = { create: 'Luo', setAmount: 'Vastaanotettava summa', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Osta Bitcoinia', diff --git a/loc/fr_FR.js b/loc/fr_FR.js index 2061fb86d..a66c590a8 100644 --- a/loc/fr_FR.js +++ b/loc/fr_FR.js @@ -167,7 +167,7 @@ module.exports = { create: 'Create', setAmount: 'Revevoir avec montant', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Acheter du Bitcoin', diff --git a/loc/hr_HR.js b/loc/hr_HR.js index ad4be6bca..e30f55b61 100644 --- a/loc/hr_HR.js +++ b/loc/hr_HR.js @@ -163,7 +163,7 @@ module.exports = { create: 'Stvori', setAmount: 'Odredi iznos za primiti', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Kupovina Bitcoina', diff --git a/loc/hu_HU.js b/loc/hu_HU.js index 247e48e29..262baef47 100644 --- a/loc/hu_HU.js +++ b/loc/hu_HU.js @@ -165,7 +165,7 @@ module.exports = { create: 'Létrehoz', setAmount: 'Fogadandó összeg', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Bitcoin vásárlása', diff --git a/loc/id_ID.js b/loc/id_ID.js index 7e00ce7c5..5edb33eb6 100644 --- a/loc/id_ID.js +++ b/loc/id_ID.js @@ -165,7 +165,7 @@ module.exports = { create: 'Buat', setAmount: 'Terima sejumlah', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Beli bitcoin', diff --git a/loc/it.js b/loc/it.js index aea71d1db..ec8dbd1fb 100644 --- a/loc/it.js +++ b/loc/it.js @@ -168,7 +168,7 @@ module.exports = { create: 'Crea', setAmount: 'Ricevi con importo', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Compra Bitcoin', diff --git a/loc/jp_JP.js b/loc/jp_JP.js index 9a3cf86ce..f3ceec3b0 100644 --- a/loc/jp_JP.js +++ b/loc/jp_JP.js @@ -165,7 +165,7 @@ module.exports = { create: '作成', setAmount: '入金額', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Bitcoin の購入', diff --git a/loc/nb_NO.js b/loc/nb_NO.js index 6cf372562..e77bf1dff 100644 --- a/loc/nb_NO.js +++ b/loc/nb_NO.js @@ -166,7 +166,7 @@ module.exports = { create: 'Lag', setAmount: 'Motta med beløp', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Kjøp Bitcoin', diff --git a/loc/nl_NL.js b/loc/nl_NL.js index e82c38abc..6124c3ab4 100644 --- a/loc/nl_NL.js +++ b/loc/nl_NL.js @@ -166,7 +166,7 @@ module.exports = { create: 'Create', setAmount: 'Ontvang met bedrag', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Koop Bitcoin', diff --git a/loc/pt_BR.js b/loc/pt_BR.js index c96c7c3f5..ef2aca917 100644 --- a/loc/pt_BR.js +++ b/loc/pt_BR.js @@ -169,7 +169,7 @@ module.exports = { create: 'Create', setAmount: 'Valor a receber', }, - scan_lnurl: 'Receber lendo QR' + scan_lnurl: 'Receber lendo QR', }, buyBitcoin: { header: 'Comprar Bitcoin', diff --git a/loc/pt_PT.js b/loc/pt_PT.js index 83dbbdcc8..a621a51c9 100644 --- a/loc/pt_PT.js +++ b/loc/pt_PT.js @@ -172,7 +172,7 @@ module.exports = { create: 'Create', setAmount: 'Receive with amount', }, - scan_lnurl: 'Receber lendo QR' + scan_lnurl: 'Receber lendo QR', }, settings: { tabBarLabel: 'Definições', diff --git a/loc/ru.js b/loc/ru.js index a4badfcce..e57590cc6 100644 --- a/loc/ru.js +++ b/loc/ru.js @@ -171,7 +171,7 @@ module.exports = { create: 'Создать', setAmount: 'Получить сумму', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, settings: { tabBarLabel: 'Настройки', diff --git a/loc/sv_SE.js b/loc/sv_SE.js index 57de74da9..451a64545 100644 --- a/loc/sv_SE.js +++ b/loc/sv_SE.js @@ -165,7 +165,7 @@ module.exports = { create: 'Skapa', setAmount: 'Ta emot med belopp', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Köp bitcoin', diff --git a/loc/th_TH.js b/loc/th_TH.js index 154dd9dbd..95ca764ad 100644 --- a/loc/th_TH.js +++ b/loc/th_TH.js @@ -165,7 +165,7 @@ module.exports = { create: 'สร้าง', setAmount: 'รับด้วยจำนวน', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'ซื้อบิตคอยน์', diff --git a/loc/tr_TR.js b/loc/tr_TR.js index c2f85cdb9..ebb8e87a9 100644 --- a/loc/tr_TR.js +++ b/loc/tr_TR.js @@ -166,7 +166,7 @@ module.exports = { create: 'Oluştur', setAmount: 'Miktar ile al', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Bitcoin Satın al', diff --git a/loc/ua.js b/loc/ua.js index 2db9c5fc4..4b86e6c94 100644 --- a/loc/ua.js +++ b/loc/ua.js @@ -166,7 +166,7 @@ module.exports = { create: 'Create', setAmount: 'Receive with amount', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: 'Buy Bitcoin', diff --git a/loc/zh_cn.js b/loc/zh_cn.js index c9b9ce145..f6b2e4156 100755 --- a/loc/zh_cn.js +++ b/loc/zh_cn.js @@ -163,7 +163,7 @@ module.exports = { create: '创建', setAmount: '收款金额', }, - scan_lnurl: 'Scan to receive' + scan_lnurl: 'Scan to receive', }, buyBitcoin: { header: '购买比特币', diff --git a/package.json b/package.json index 0d1477328..969c3eaea 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "coinselect": "3.1.11", "crypto-js": "3.1.9-1", "dayjs": "1.8.14", - "electrum-client": "git+https://github.com/Overtorment/rn-electrum-client.git", + "electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git", "eslint-config-prettier": "6.0.0", "eslint-config-standard": "12.0.0", "eslint-config-standard-react": "7.0.2", diff --git a/react-native.config.js b/react-native.config.js index 495d68020..daa0bcdb9 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -1,6 +1,6 @@ module.exports = { dependencies: { - 'appcenter': { + appcenter: { platforms: { android: null, // disable Android platform, other platforms will still autolink if provided }, diff --git a/screen/lnd/lndCreateInvoice.js b/screen/lnd/lndCreateInvoice.js index ea6dde0b8..ea0e0c5da 100644 --- a/screen/lnd/lndCreateInvoice.js +++ b/screen/lnd/lndCreateInvoice.js @@ -1,6 +1,16 @@ /* global alert */ import React, { Component } from 'react'; -import { Dimensions, ActivityIndicator, View, TextInput, KeyboardAvoidingView, Keyboard, TouchableWithoutFeedback, TouchableOpacity, Text } from 'react-native'; +import { + Dimensions, + ActivityIndicator, + View, + TextInput, + KeyboardAvoidingView, + Keyboard, + TouchableWithoutFeedback, + TouchableOpacity, + Text, +} from 'react-native'; import { BlueNavigationStyle, BlueButton, BlueBitcoinAmount, BlueDismissKeyboardInputAccessory } from '../../BlueComponents'; import PropTypes from 'prop-types'; import bech32 from 'bech32'; @@ -42,9 +52,9 @@ export default class LNDCreateInvoice extends Component { // send to lnurl-withdraw callback url if that exists if (this.state.lnurlParams) { - let {callback, k1} = this.state.lnurlParams; + let { callback, k1 } = this.state.lnurlParams; let callbackUrl = callback + (callback.indexOf('?') !== -1 ? '&' : '?') + 'k1=' + k1 + '&pr=' + invoiceRequest; - let resp = await fetch(callbackUrl, {method: 'GET'}); + let resp = await fetch(callbackUrl, { method: 'GET' }); if (resp.status >= 300) { let text = await resp.text(); throw new Error(text); @@ -91,9 +101,9 @@ export default class LNDCreateInvoice extends Component { // calling the url try { - let resp = await fetch(url, {method: 'GET'}) + let resp = await fetch(url, { method: 'GET' }); if (resp.status >= 300) { - throw new Error("Bad response from server"); + throw new Error('Bad response from server'); } let reply = await resp.json(); if (reply.status === 'ERROR') { @@ -112,7 +122,7 @@ export default class LNDCreateInvoice extends Component { callback: reply.callback, fixed: reply.minWithdrawable === reply.maxWithdrawable, min: (reply.minWithdrawable || 0) / 1000, - max: reply.maxWithdrawable / 1000 + max: reply.maxWithdrawable / 1000, }, amount: (reply.maxWithdrawable / 1000).toString(), description: reply.defaultDescription, @@ -124,7 +134,7 @@ export default class LNDCreateInvoice extends Component { alert(Err.message); } }); - } + }; renderCreateButton = () => { return ( @@ -142,18 +152,16 @@ export default class LNDCreateInvoice extends Component { return ( NavigationService.navigate('ScanQrAddress', { onBarScanned: this.processLnurl }) } + onPress={() => NavigationService.navigate('ScanQrAddress', { onBarScanned: this.processLnurl })} style={{ flex: 1, flexDirection: 'row', minWidth: width, justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', }} > - - {loc.receive.scan_lnurl} - + {loc.receive.scan_lnurl} ); @@ -179,12 +187,12 @@ export default class LNDCreateInvoice extends Component { onChangeText={text => { if (this.state.lnurlParams) { // in this case we prevent the user from changing the amount to < min or > max - let {min, max} = this.state.lnurlParams; - let nextAmount = parseInt(text) + let { min, max } = this.state.lnurlParams; + let nextAmount = parseInt(text); if (nextAmount < min) { - text = min.toString() + text = min.toString(); } else if (nextAmount > max) { - text = max.toString() + text = max.toString(); } } diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 5a0ab8011..94926043c 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -1,16 +1,6 @@ /* global alert */ import React, { Component } from 'react'; -import { - Text, - View, - ActivityIndicator, - InteractionManager, - FlatList, - RefreshControl, - TouchableOpacity, - StatusBar, - StyleSheet, -} from 'react-native'; +import { Text, View, ActivityIndicator, InteractionManager, FlatList, RefreshControl, TouchableOpacity, StatusBar } from 'react-native'; import PropTypes from 'prop-types'; import { NavigationEvents } from 'react-navigation'; import { BlueSendButtonIcon, BlueReceiveButtonIcon, BlueTransactionListItem, BlueWalletNavigationHeader } from '../../BlueComponents'; @@ -392,11 +382,3 @@ WalletTransactions.propTypes = { setParams: PropTypes.func, }), }; - -const styles = StyleSheet.create({ - balance: { - flexDirection: 'row', - alignItems: 'center', - marginTop: 8, - }, -}); From b5aafee38fd7aaf60232625cfebeb9009dd9af9c Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Mon, 5 Aug 2019 11:25:36 -0400 Subject: [PATCH 03/10] FIX: Fixed Send Max UI to fit design --- BlueComponents.js | 16 ++++++++++++++-- screen/send/details.js | 27 +++++++++------------------ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index ae6ee094f..8cea9d399 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -767,11 +767,23 @@ export class BlueUseAllFundsButton extends Component { render() { return ( - + Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} - + + {this.props.wallet.allowSendMax() && } + + ); diff --git a/screen/send/details.js b/screen/send/details.js index ee5547f41..3d2bc86f4 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -23,6 +23,7 @@ import { BlueDismissKeyboardInputAccessory, BlueLoading, BlueButtonLink, + BlueUseAllFundsButton, } from '../../BlueComponents'; import Slider from '@react-native-community/slider'; import PropTypes from 'prop-types'; @@ -634,25 +635,8 @@ export default class SendDetails extends Component { isLoading={this.state.isLoading} amount={this.state.amount.toString()} onChangeText={text => this.setState({ amount: text })} - onBlur={() => { - this.setState({ showSendMax: false }); - }} - onFocus={() => { - this.setState({ showSendMax: true }); - }} - inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID} + inputAccessoryViewID={this.state.fromWallet.allowSendMax() ? BlueUseAllFundsButton.InputAccessoryViewID : null} /> - {this.state.showSendMax && this.state.fromWallet.allowSendMax() && ( - - { - console.log('state was set'); - this.setState({ amount: 'MAX' }); - }} - /> - - )} { if (!this.processBIP70Invoice(text)) { @@ -736,6 +720,13 @@ export default class SendDetails extends Component { + { + this.setState({ amount: 'MAX' }); + Keyboard.dismiss(); + }} + wallet={this.state.fromWallet} + /> {this.renderWalletSelectionButton()} From 21d8bf59c60fe40a04825cc95fbcb9bbe0b8f45b Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Mon, 5 Aug 2019 11:35:49 -0400 Subject: [PATCH 04/10] FIX: Place Use All closer to amount --- BlueComponents.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index 8cea9d399..eeda4b79a 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -777,11 +777,13 @@ export class BlueUseAllFundsButton extends Component { backgroundColor: '#eef0f4', }} > - - Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} - - + + + Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} + {this.props.wallet.allowSendMax() && } + + From fa29c645cc79197995263ac580d908fd2ed75a79 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Mon, 5 Aug 2019 18:25:36 -0400 Subject: [PATCH 05/10] FIX: Toolbar now visible for Android --- BlueComponents.js | 50 +++++++++++++++++++++++------------------- package-lock.json | 4 ++-- screen/send/details.js | 35 +++++++++++++++++++++-------- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index eeda4b79a..acef6514c 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -11,6 +11,7 @@ import { Animated, ActivityIndicator, View, + KeyboardAvoidingView, UIManager, StyleSheet, Dimensions, @@ -765,30 +766,35 @@ export class BlueUseAllFundsButton extends Component { }; render() { - return ( - - - - - Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} - - {this.props.wallet.allowSendMax() && } - - - - + const inputView = ( + + + + Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} + + {this.props.wallet.allowSendMax() && this.props.wallet.balance > 0 && ( + + )} - + + + + ); + if (Platform.OS === 'ios') { + return {inputView}; + } else { + return {inputView}; + } } } diff --git a/package-lock.json b/package-lock.json index fba4ae4cb..17cf8929f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3956,8 +3956,8 @@ "integrity": "sha512-SfD7WfmueKrtKeHUESLczuANgnpdnfrSz3ZzerLdtmZf2UBZmAB3z9Q525zI5p3n9I7ii/lllUlyKHm2pIG7QQ==" }, "electrum-client": { - "version": "git+https://github.com/Overtorment/rn-electrum-client.git#d194ff69195ccc86f72088ea3712179b4be9cbb4", - "from": "git+https://github.com/Overtorment/rn-electrum-client.git" + "version": "git+https://github.com/BlueWallet/rn-electrum-client.git#d194ff69195ccc86f72088ea3712179b4be9cbb4", + "from": "git+https://github.com/BlueWallet/rn-electrum-client.git" }, "elliptic": { "version": "6.5.0", diff --git a/screen/send/details.js b/screen/send/details.js index 3d2bc86f4..3a1d28f12 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -22,7 +22,6 @@ import { BlueAddressInput, BlueDismissKeyboardInputAccessory, BlueLoading, - BlueButtonLink, BlueUseAllFundsButton, } from '../../BlueComponents'; import Slider from '@react-native-community/slider'; @@ -73,7 +72,7 @@ export default class SendDetails extends Component { fromSecret = fromWallet.getSecret(); } this.state = { - isLoading: true, + isLoading: false, showSendMax: false, isFeeSelectionModalVisible: false, fromAddress, @@ -636,6 +635,8 @@ export default class SendDetails extends Component { amount={this.state.amount.toString()} onChangeText={text => this.setState({ amount: text })} inputAccessoryViewID={this.state.fromWallet.allowSendMax() ? BlueUseAllFundsButton.InputAccessoryViewID : null} + onFocus={() => this.setState({ isAmountToolbarVisibleForAndroid: true })} + onBlur={() => this.setState({ isAmountToolbarVisibleForAndroid: false })} /> { @@ -720,13 +721,29 @@ export default class SendDetails extends Component { - { - this.setState({ amount: 'MAX' }); - Keyboard.dismiss(); - }} - wallet={this.state.fromWallet} - /> + {Platform.select({ + ios: ( + { + this.setState({ amount: 'MAX' }); + Keyboard.dismiss(); + }} + wallet={this.state.fromWallet} + visi + /> + ), + android: this.state.isAmountToolbarVisibleForAndroid && ( + { + this.setState({ amount: 'MAX' }); + Keyboard.dismiss(); + }} + wallet={this.state.fromWallet} + visi + /> + ), + })} + {this.renderWalletSelectionButton()} From 221df241003a8e3ad3db2bda1d1a66a8cffcae4b Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Mon, 5 Aug 2019 23:40:09 -0400 Subject: [PATCH 06/10] FIX: placeholder amount bug --- screen/send/details.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/screen/send/details.js b/screen/send/details.js index 3a1d28f12..d4130bf70 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -80,7 +80,6 @@ export default class SendDetails extends Component { fromSecret, address, memo, - amount: 0, fee: 1, networkTransactionFees: new NetworkTransactionFee(1, 1, 1), feeSliderValue: 1, @@ -632,7 +631,7 @@ export default class SendDetails extends Component { this.setState({ amount: text })} inputAccessoryViewID={this.state.fromWallet.allowSendMax() ? BlueUseAllFundsButton.InputAccessoryViewID : null} onFocus={() => this.setState({ isAmountToolbarVisibleForAndroid: true })} From 3cee26be26207e9a40d597beabc99c7853ad4cac Mon Sep 17 00:00:00 2001 From: ncoelho Date: Tue, 6 Aug 2019 20:47:16 +0200 Subject: [PATCH 07/10] Align send max option on the UI Align send max option on the UI --- BlueComponents.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index acef6514c..29f4d9bc8 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -777,16 +777,16 @@ export class BlueUseAllFundsButton extends Component { backgroundColor: '#eef0f4', }} > - - - Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC} + + + {this.props.wallet.getBalance()} {BitcoinUnit.BTC} {this.props.wallet.allowSendMax() && this.props.wallet.balance > 0 && ( - + )} - + ); From 676cf112e70c8594f7dae37c6a18778aacaf98e2 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Tue, 6 Aug 2019 21:42:41 -0400 Subject: [PATCH 08/10] FIX: Fix Send max toolbar calculation --- BlueComponents.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index 29f4d9bc8..0c0d38853 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -778,15 +778,34 @@ export class BlueUseAllFundsButton extends Component { }} > - - {this.props.wallet.getBalance()} {BitcoinUnit.BTC} + + Total: {loc.formatBalanceWithoutSuffix(this.props.wallet.getBalance(), BitcoinUnit.BTC, true).toString()} {BitcoinUnit.BTC} - {this.props.wallet.allowSendMax() && this.props.wallet.balance > 0 && ( - + {this.props.wallet.allowSendMax() && this.props.wallet.getBalance() > 0 && ( + )} - + ); From ff0f7d17b930e878702ae969dec7c825f541644f Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Date: Wed, 7 Aug 2019 01:45:27 -0400 Subject: [PATCH 09/10] ADD: User confirmation for use of all funds. --- BlueComponents.js | 25 +++++++++++++++++++++---- screen/send/details.js | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index 0c0d38853..3326360b9 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -790,14 +790,31 @@ export class BlueUseAllFundsButton extends Component { paddingBottom: 12, }} > - Total: {loc.formatBalanceWithoutSuffix(this.props.wallet.getBalance(), BitcoinUnit.BTC, true).toString()} {BitcoinUnit.BTC} + Total: - {this.props.wallet.allowSendMax() && this.props.wallet.getBalance() > 0 && ( + {this.props.wallet.allowSendMax() ? ( + ) : ( + + {loc.formatBalanceWithoutSuffix(this.props.wallet.getBalance(), BitcoinUnit.BTC, true).toString()} {BitcoinUnit.BTC} + )} diff --git a/screen/send/details.js b/screen/send/details.js index d4130bf70..58b64dd63 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -4,6 +4,7 @@ import { ActivityIndicator, View, TextInput, + Alert, StatusBar, TouchableOpacity, KeyboardAvoidingView, @@ -724,21 +725,48 @@ export default class SendDetails extends Component { ios: ( { - this.setState({ amount: 'MAX' }); + ReactNativeHapticFeedback.trigger('notificationWarning'); + Alert.alert( + 'Use full balance', + `Are you sure you want to use your wallet's full balance for this transaction?`, + [ + { + text: loc._.ok, + onPress: async () => { + this.setState({ amount: 'MAX' }); + }, + style: 'default', + }, + { text: loc.send.details.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); Keyboard.dismiss(); }} wallet={this.state.fromWallet} - visi /> ), android: this.state.isAmountToolbarVisibleForAndroid && ( { - this.setState({ amount: 'MAX' }); + Alert.alert( + 'Use all funds', + `Are you sure you want to use your all of your wallet's funds for this transaction?`, + [ + { + text: loc._.ok, + onPress: async () => { + this.setState({ amount: 'MAX' }); + }, + style: 'default', + }, + { text: loc.send.details.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); Keyboard.dismiss(); }} wallet={this.state.fromWallet} - visi /> ), })} From ae519aceb958d0c3de1893429c66983c0f8489cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Rodriguez=20V=C3=A9lez?= Date: Wed, 7 Aug 2019 10:29:28 -0400 Subject: [PATCH 10/10] Update BlueComponents.js --- BlueComponents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueComponents.js b/BlueComponents.js index 3326360b9..f1e53a47f 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -792,7 +792,7 @@ export class BlueUseAllFundsButton extends Component { > Total: - {this.props.wallet.allowSendMax() ? ( + {this.props.wallet.allowSendMax() && this.props.wallet.getBalance() > 0 ? (