From 5013f847ed80aa50449dc4135384679cf265a389 Mon Sep 17 00:00:00 2001 From: Ivan Vershigora Date: Thu, 18 Mar 2021 13:39:48 +0300 Subject: [PATCH] ADD: allow send MAX and BATCH for all wallet types --- class/wallets/abstract-wallet.js | 8 - class/wallets/hd-aezeed-wallet.js | 8 - class/wallets/hd-legacy-breadwallet-wallet.js | 4 - .../hd-legacy-electrum-seed-p2pkh-wallet.js | 4 - class/wallets/hd-legacy-p2pkh-wallet.js | 4 - class/wallets/hd-segwit-bech32-wallet.js | 8 - .../hd-segwit-electrum-seed-p2wpkh-wallet.js | 4 - class/wallets/hd-segwit-p2sh-wallet.js | 4 - class/wallets/legacy-wallet.js | 4 - class/wallets/multisig-hd-wallet.js | 4 - class/wallets/segwit-bech32-wallet.js | 4 - class/wallets/segwit-p2sh-wallet.js | 4 - class/wallets/watch-only-wallet.js | 14 -- loc/en.json | 3 - screen/send/details.js | 161 +++++------------- tests/unit/legacy-wallet.test.js | 13 ++ tests/unit/segwit-bech32-wallet.test.js | 13 ++ 17 files changed, 68 insertions(+), 196 deletions(-) diff --git a/class/wallets/abstract-wallet.js b/class/wallets/abstract-wallet.js index c9e1c6f41..ba67e08dc 100644 --- a/class/wallets/abstract-wallet.js +++ b/class/wallets/abstract-wallet.js @@ -100,18 +100,10 @@ export class AbstractWallet { return true; } - allowSendMax(): boolean { - return false; - } - allowRBF() { return false; } - allowBatchSend() { - return false; - } - allowHodlHodlTrading() { return false; } diff --git a/class/wallets/hd-aezeed-wallet.js b/class/wallets/hd-aezeed-wallet.js index 763be3507..f0a742764 100644 --- a/class/wallets/hd-aezeed-wallet.js +++ b/class/wallets/hd-aezeed-wallet.js @@ -142,14 +142,6 @@ export class HDAezeedWallet extends AbstractHDElectrumWallet { return true; } - allowBatchSend() { - return true; - } - - allowSendMax() { - return true; - } - allowHodlHodlTrading() { return true; } diff --git a/class/wallets/hd-legacy-breadwallet-wallet.js b/class/wallets/hd-legacy-breadwallet-wallet.js index f422b42b3..0db7edcd3 100644 --- a/class/wallets/hd-legacy-breadwallet-wallet.js +++ b/class/wallets/hd-legacy-breadwallet-wallet.js @@ -17,10 +17,6 @@ export class HDLegacyBreadwalletWallet extends HDLegacyP2PKHWallet { _external_segwit_index = null; // eslint-disable-line camelcase _internal_segwit_index = null; // eslint-disable-line camelcase - allowSendMax() { - return true; - } - /** * @see https://github.com/bitcoinjs/bitcoinjs-lib/issues/584 * @see https://github.com/bitcoinjs/bitcoinjs-lib/issues/914 diff --git a/class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.js b/class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.js index 931429b17..8d1f16b50 100644 --- a/class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.js +++ b/class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.js @@ -69,10 +69,6 @@ export class HDLegacyElectrumSeedP2PKHWallet extends HDLegacyP2PKHWallet { return child.toWIF(); } - allowSendMax() { - return true; - } - _getNodePubkeyByIndex(node, index) { index = index * 1; // cast to int diff --git a/class/wallets/hd-legacy-p2pkh-wallet.js b/class/wallets/hd-legacy-p2pkh-wallet.js index 21de572d0..207fc3403 100644 --- a/class/wallets/hd-legacy-p2pkh-wallet.js +++ b/class/wallets/hd-legacy-p2pkh-wallet.js @@ -17,10 +17,6 @@ export class HDLegacyP2PKHWallet extends AbstractHDElectrumWallet { return true; } - allowSendMax() { - return true; - } - allowCosignPsbt() { return true; } diff --git a/class/wallets/hd-segwit-bech32-wallet.js b/class/wallets/hd-segwit-bech32-wallet.js index a453e5eb9..9a0399ece 100644 --- a/class/wallets/hd-segwit-bech32-wallet.js +++ b/class/wallets/hd-segwit-bech32-wallet.js @@ -14,14 +14,6 @@ export class HDSegwitBech32Wallet extends AbstractHDElectrumWallet { return true; } - allowBatchSend() { - return true; - } - - allowSendMax() { - return true; - } - allowHodlHodlTrading() { return true; } diff --git a/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.js b/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.js index 28540bd60..5c82d1d0d 100644 --- a/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.js +++ b/class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.js @@ -69,10 +69,6 @@ export class HDSegwitElectrumSeedP2WPKHWallet extends HDSegwitBech32Wallet { return child.toWIF(); } - allowSendMax() { - return true; - } - _getNodePubkeyByIndex(node, index) { index = index * 1; // cast to int diff --git a/class/wallets/hd-segwit-p2sh-wallet.js b/class/wallets/hd-segwit-p2sh-wallet.js index be3a98757..dfbdb12b4 100644 --- a/class/wallets/hd-segwit-p2sh-wallet.js +++ b/class/wallets/hd-segwit-p2sh-wallet.js @@ -18,10 +18,6 @@ export class HDSegwitP2SHWallet extends AbstractHDElectrumWallet { return true; } - allowSendMax(): boolean { - return true; - } - allowCosignPsbt() { return true; } diff --git a/class/wallets/legacy-wallet.js b/class/wallets/legacy-wallet.js index d4beacbc7..fcd5c8bb0 100644 --- a/class/wallets/legacy-wallet.js +++ b/class/wallets/legacy-wallet.js @@ -476,10 +476,6 @@ export class LegacyWallet extends AbstractWallet { return false; } - allowSendMax() { - return true; - } - allowSignVerifyMessage() { return true; } diff --git a/class/wallets/multisig-hd-wallet.js b/class/wallets/multisig-hd-wallet.js index a1f8357fd..b6b456626 100644 --- a/class/wallets/multisig-hd-wallet.js +++ b/class/wallets/multisig-hd-wallet.js @@ -1108,10 +1108,6 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet { return /^[0-9A-F]{8}$/i.test(fp); } - allowBatchSend() { - return true; - } - /** * Returns TRUE only for _multisignature_ xpubs as per SLIP-0132 * (capital Z, capital Y, or just xpub) diff --git a/class/wallets/segwit-bech32-wallet.js b/class/wallets/segwit-bech32-wallet.js index 721f4fa90..10223c62f 100644 --- a/class/wallets/segwit-bech32-wallet.js +++ b/class/wallets/segwit-bech32-wallet.js @@ -130,10 +130,6 @@ export class SegwitBech32Wallet extends LegacyWallet { return true; } - allowSendMax() { - return true; - } - allowSignVerifyMessage() { return true; } diff --git a/class/wallets/segwit-p2sh-wallet.js b/class/wallets/segwit-p2sh-wallet.js index 8dbce9887..f07c77cd3 100644 --- a/class/wallets/segwit-p2sh-wallet.js +++ b/class/wallets/segwit-p2sh-wallet.js @@ -139,10 +139,6 @@ export class SegwitP2SHWallet extends LegacyWallet { return { tx, inputs, outputs, fee, psbt }; } - allowSendMax() { - return true; - } - allowSignVerifyMessage() { return true; } diff --git a/class/wallets/watch-only-wallet.js b/class/wallets/watch-only-wallet.js index 9cff25b13..389c4ca7d 100644 --- a/class/wallets/watch-only-wallet.js +++ b/class/wallets/watch-only-wallet.js @@ -21,20 +21,6 @@ export class WatchOnlyWallet extends LegacyWallet { ); } - allowBatchSend() { - return ( - this.useWithHardwareWalletEnabled() && - this._hdWalletInstance instanceof HDSegwitBech32Wallet && - this._hdWalletInstance.allowBatchSend() - ); - } - - allowSendMax() { - return ( - this.useWithHardwareWalletEnabled() && this._hdWalletInstance instanceof HDSegwitBech32Wallet && this._hdWalletInstance.allowSendMax() - ); - } - getAddress() { if (this.isAddressValid(this.secret)) return this.secret; // handling case when there is an XPUB there if (this._hdWalletInstance) throw new Error('Should not be used in watch-only HD wallets'); diff --git a/loc/en.json b/loc/en.json index d1ced1732..0f06f4964 100644 --- a/loc/en.json +++ b/loc/en.json @@ -183,15 +183,12 @@ "details_error_decode": "Unable to decode Bitcoin address", "details_fee_field_is_not_valid": "The fee is not valid.", "details_next": "Next", - "details_no_maximum": "The selected wallet doesn’t support automatic maximum balance calculation. Are you sure to want to select this wallet?", - "details_no_multiple": "The selected wallet doesn’t support sending bitcoin to multiple recipients. Are you sure to want to select this wallet?", "details_no_signed_tx": "The selected file doesn’t contain a transaction that can be imported.", "details_note_placeholder": "Note to Self", "details_scan": "Scan", "details_total_exceeds_balance": "The sending amount exceeds the available balance.", "details_unrecognized_file_format": "Unrecognized file format", "details_wallet_before_tx": "Before creating a transaction, you must first add a Bitcoin wallet.", - "details_wallet_selection": "Wallet Selection", "dynamic_init": "Initializing", "dynamic_next": "Next", "dynamic_prev": "Previous", diff --git a/screen/send/details.js b/screen/send/details.js index a06a6bcf0..b07d40383 100644 --- a/screen/send/details.js +++ b/screen/send/details.js @@ -184,7 +184,6 @@ const SendDetails = () => { if (!wallet) return; setSelectedWallet(wallet.getID()); navigation.setParams({ - withAdvancedOptionsMenuButton: wallet.allowBatchSend() || wallet.allowSendMax(), advancedOptionsMenuButtonAction: () => { Keyboard.dismiss(); setOptionsVisible(true); @@ -400,7 +399,7 @@ const SendDetails = () => { } else if (!transaction.address) { error = loc.send.details_address_field_is_not_valid; console.log('validation error'); - } else if (wallet.getBalance() - transaction.amountSats < 0) { + } else if (balance - transaction.amountSats < 0) { // first sanity check is that sending amount is not bigger than available balance error = loc.send.details_total_exceeds_balance; console.log('validation error'); @@ -517,59 +516,8 @@ const SendDetails = () => { }; const onWalletSelect = wallet => { - const changeWallet = () => { - setWallet(wallet); - navigation.pop(); - }; - - if (addresses.length > 1 && !wallet.allowBatchSend()) { - ReactNativeHapticFeedback.trigger('notificationWarning'); - Alert.alert( - loc.send.details_wallet_selection, - loc.send.details_no_multiple, - [ - { - text: loc._.ok, - onPress: async () => { - const firstTransaction = - addresses.find(element => { - const feeSatoshi = new BigNumber(element.amount).multipliedBy(100000000); - return element.address.length > 0 && feeSatoshi > 0; - }) || addresses[0]; - LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); - setAddresses([firstTransaction]); - changeWallet(); - }, - style: 'default', - }, - { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, - ], - { cancelable: false }, - ); - } else if (addresses.some(element => element.amount === BitcoinUnit.MAX) && !wallet.allowSendMax()) { - ReactNativeHapticFeedback.trigger('notificationWarning'); - Alert.alert( - loc.send.details_wallet_selection, - loc.send.details_no_maximum, - [ - { - text: loc._.ok, - onPress: async () => { - const firstTransaction = addresses.find(element => element.amount === BitcoinUnit.MAX) || addresses[0]; - firstTransaction.amount = 0; - LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); - setAddresses([firstTransaction]); - changeWallet(); - }, - style: 'default', - }, - { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, - ], - { cancelable: false }, - ); - } else { - changeWallet(); - } + setWallet(wallet); + navigation.pop(); }; /** @@ -1038,16 +986,14 @@ const SendDetails = () => { - {wallet.allowSendMax() && ( - 0) || isSendMaxUsed} - title={loc.send.details_adv_full} - hideChevron - component={TouchableOpacity} - onPress={onUseAllPressed} - /> - )} + {wallet.type === HDSegwitBech32Wallet.type && ( { onPress={importTransactionMultisigScanQr} /> )} - {wallet.allowBatchSend() && ( - <> - - - - )} + + {wallet.allowCosignPsbt() && ( { setAddresses([...addresses]); }} unit={units[index] || amountUnit} - inputAccessoryViewID={wallet.allowSendMax() ? BlueUseAllFundsButton.InputAccessoryViewID : null} + inputAccessoryViewID={BlueUseAllFundsButton.InputAccessoryViewID} /> { @@ -1315,19 +1256,9 @@ const SendDetails = () => { {Platform.select({ - ios: ( - 0} - onUseAllPressed={onUseAllPressed} - balance={allBalance} - /> - ), + ios: 0} onUseAllPressed={onUseAllPressed} balance={allBalance} />, android: isAmountToolbarVisibleForAndroid && ( - 0} - onUseAllPressed={onUseAllPressed} - balance={allBalance} - /> + 0} onUseAllPressed={onUseAllPressed} balance={allBalance} /> ), })} @@ -1475,24 +1406,16 @@ const styles = StyleSheet.create({ }, }); -SendDetails.navigationOptions = navigationStyleTx({}, (options, { theme, navigation, route }) => { - let headerRight; - if (route.params.withAdvancedOptionsMenuButton) { - headerRight = () => ( - - - - ); - } else { - headerRight = null; - } - return { - ...options, - headerRight, - title: loc.send.header, - }; -}); +SendDetails.navigationOptions = navigationStyleTx({}, (options, { theme, navigation, route }) => ({ + ...options, + headerRight: () => ( + + + + ), + title: loc.send.header, +})); diff --git a/tests/unit/legacy-wallet.test.js b/tests/unit/legacy-wallet.test.js index cf12a7a51..faef25a3f 100644 --- a/tests/unit/legacy-wallet.test.js +++ b/tests/unit/legacy-wallet.test.js @@ -38,6 +38,19 @@ describe('Legacy wallet', () => { assert.strictEqual(tx.ins.length, 1); assert.strictEqual(tx.outs.length, 1); assert.strictEqual('1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB', bitcoin.address.fromOutputScript(tx.outs[0].script)); // to address + + // batch send + send max + txNew = l.createTransaction( + utxos, + [{ address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }, { address: 'bc1q3rl0mkyk0zrtxfmqn9wpcd3gnaz00yv9yp0hxe', value: 10000 }], + 1, + l.getAddress(), + ); + tx = bitcoin.Transaction.fromHex(txNew.tx.toHex()); + assert.strictEqual(tx.ins.length, 1); + assert.strictEqual(tx.outs.length, 2); + assert.strictEqual('1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB', bitcoin.address.fromOutputScript(tx.outs[0].script)); // to address + assert.strictEqual('bc1q3rl0mkyk0zrtxfmqn9wpcd3gnaz00yv9yp0hxe', bitcoin.address.fromOutputScript(tx.outs[1].script)); // to address }); it("throws error if you can't create wallet from this entropy", async () => { diff --git a/tests/unit/segwit-bech32-wallet.test.js b/tests/unit/segwit-bech32-wallet.test.js index 8700ab85a..6dca7846c 100644 --- a/tests/unit/segwit-bech32-wallet.test.js +++ b/tests/unit/segwit-bech32-wallet.test.js @@ -35,6 +35,19 @@ describe('Segwit P2SH wallet', () => { assert.strictEqual(tx.ins.length, 1); assert.strictEqual(tx.outs.length, 1); assert.strictEqual('1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB', bitcoin.address.fromOutputScript(tx.outs[0].script)); // to address + + // batch send + send max + txNew = wallet.createTransaction( + utxos, + [{ address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }, { address: '14YZ6iymQtBVQJk6gKnLCk49UScJK7SH4M', value: 10000 }], + 1, + wallet.getAddress(), + ); + tx = bitcoin.Transaction.fromHex(txNew.tx.toHex()); + assert.strictEqual(tx.ins.length, 1); + assert.strictEqual(tx.outs.length, 2); + assert.strictEqual('1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB', bitcoin.address.fromOutputScript(tx.outs[0].script)); // to address + assert.strictEqual('14YZ6iymQtBVQJk6gKnLCk49UScJK7SH4M', bitcoin.address.fromOutputScript(tx.outs[1].script)); // to address }); it('can sign and verify messages', async () => {