mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 09:50:15 +01:00
Merge pull request #4317 from BlueWallet/limpbrains-frozen
ADD: show frozen amount on send screen, warn in case of send MAX or amount exeeds balance
This commit is contained in:
commit
78be074f1f
@ -211,6 +211,7 @@
|
||||
"details_adv_fee_bump": "Allow Fee Bump",
|
||||
"details_adv_full": "Use Full Balance",
|
||||
"details_adv_full_sure": "Are you sure you want to use your wallet’s full balance for this transaction?",
|
||||
"details_adv_full_sure_frozen": "Are you sure you want to use your wallet’s full balance for this transaction? Please note that frozen coins are excluded.",
|
||||
"details_adv_import": "Import Transaction",
|
||||
"details_adv_import_qr": "Import Transaction (QR)",
|
||||
"details_amount_field_is_not_valid": "The amount is not valid.",
|
||||
@ -218,12 +219,14 @@
|
||||
"details_create": "Create Invoice",
|
||||
"details_error_decode": "Unable to decode Bitcoin address",
|
||||
"details_fee_field_is_not_valid": "The fee is not valid.",
|
||||
"details_frozen": "{amount} BTC are frozen",
|
||||
"details_next": "Next",
|
||||
"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_scan_hint": "Double tap to scan or import a destination",
|
||||
"details_total_exceeds_balance": "The sending amount exceeds the available balance.",
|
||||
"details_total_exceeds_balance_frozen": "The sending amount exceeds the available balance. Please note that the frozen coins are excluded.",
|
||||
"details_unrecognized_file_format": "Unrecognized file format",
|
||||
"details_wallet_before_tx": "Before creating a transaction, you must first add a Bitcoin wallet.",
|
||||
"dynamic_init": "Initializing",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useRef, useEffect, useContext, useMemo } from 'react';
|
||||
import React, { useState, useRef, useEffect, useCallback, useContext, useMemo } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
@ -17,7 +17,7 @@ import {
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
|
||||
import { useNavigation, useRoute, useTheme, useFocusEffect } from '@react-navigation/native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
@ -25,7 +25,7 @@ import RNFS from 'react-native-fs';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
|
||||
import { BlueButton, BlueDismissKeyboardInputAccessory, BlueListItem, BlueLoading } from '../../BlueComponents';
|
||||
import { BlueButton, BlueDismissKeyboardInputAccessory, BlueListItem, BlueLoading, BlueText } from '../../BlueComponents';
|
||||
import { navigationStyleTx } from '../../components/navigationStyle';
|
||||
import NetworkTransactionFees, { NetworkTransactionFee } from '../../models/networkTransactionFees';
|
||||
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
|
||||
@ -74,6 +74,7 @@ const SendDetails = () => {
|
||||
const [feeUnit, setFeeUnit] = useState();
|
||||
const [amountUnit, setAmountUnit] = useState();
|
||||
const [utxo, setUtxo] = useState(null);
|
||||
const [frozenBalance, setFrozenBlance] = useState(false);
|
||||
const [payjoinUrl, setPayjoinUrl] = useState(null);
|
||||
const [changeAddress, setChangeAddress] = useState();
|
||||
const [dumb, setDumb] = useState(false);
|
||||
@ -252,6 +253,14 @@ const SendDetails = () => {
|
||||
const changeAddress = getChangeAddressFast();
|
||||
const requestedSatPerByte = Number(feeRate);
|
||||
const lutxo = utxo || wallet.getUtxo();
|
||||
let frozen = 0;
|
||||
if (!utxo) {
|
||||
// if utxo is not limited search for frozen outputs and calc it's balance
|
||||
frozen = wallet
|
||||
.getUtxo(true)
|
||||
.filter(o => !lutxo.some(i => i.txid === o.txid && i.vout === o.vout))
|
||||
.reduce((prev, curr) => prev + curr.value, 0);
|
||||
}
|
||||
|
||||
const options = [
|
||||
{ key: 'current', fee: requestedSatPerByte },
|
||||
@ -316,8 +325,17 @@ const SendDetails = () => {
|
||||
}
|
||||
|
||||
setFeePrecalc(newFeePrecalc);
|
||||
setFrozenBlance(frozen);
|
||||
}, [wallet, networkTransactionFees, utxo, addresses, feeRate, dumb]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
// we need to re-calculate fees if user opens-closes coin control
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
setDumb(v => !v);
|
||||
}, []),
|
||||
);
|
||||
|
||||
const getChangeAddressFast = () => {
|
||||
if (changeAddress) return changeAddress; // cache
|
||||
|
||||
@ -445,7 +463,7 @@ const SendDetails = () => {
|
||||
console.log('validation error');
|
||||
} 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;
|
||||
error = frozenBalance > 0 ? loc.send.details_total_exceeds_balance_frozen : loc.send.details_total_exceeds_balance;
|
||||
console.log('validation error');
|
||||
} else if (transaction.address) {
|
||||
const address = transaction.address.trim().toLowerCase();
|
||||
@ -977,9 +995,10 @@ const SendDetails = () => {
|
||||
|
||||
const onUseAllPressed = () => {
|
||||
ReactNativeHapticFeedback.trigger('notificationWarning');
|
||||
const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure;
|
||||
Alert.alert(
|
||||
loc.send.details_adv_full,
|
||||
loc.send.details_adv_full_sure,
|
||||
message,
|
||||
[
|
||||
{
|
||||
text: loc._.ok,
|
||||
@ -1368,6 +1387,15 @@ const SendDetails = () => {
|
||||
disabled={!isEditable}
|
||||
inputAccessoryViewID={InputAccessoryAllFunds.InputAccessoryViewID}
|
||||
/>
|
||||
|
||||
{frozenBalance > 0 && (
|
||||
<TouchableOpacity style={styles.frozenContainer} onPress={handleCoinControl}>
|
||||
<BlueText>
|
||||
{loc.formatString(loc.send.details_frozen, { amount: formatBalanceWithoutSuffix(frozenBalance, BitcoinUnit.BTC, true) })}
|
||||
</BlueText>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
<AddressInput
|
||||
onChangeText={text => {
|
||||
text = text.trim();
|
||||
@ -1637,6 +1665,12 @@ const styles = StyleSheet.create({
|
||||
height: 40,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
frozenContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginVertical: 8,
|
||||
},
|
||||
});
|
||||
|
||||
SendDetails.navigationOptions = navigationStyleTx({}, options => ({
|
||||
|
Loading…
Reference in New Issue
Block a user