Browse Source

follow-up prev: some clean-ups

re https://github.com/spesmilo/electrum/pull/7492
patch-4
SomberNight 3 years ago
parent
commit
acbb363240
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 6
      electrum/gui/kivy/main_window.py
  2. 18
      electrum/gui/qt/main_window.py
  3. 2
      electrum/invoices.py
  4. 6
      electrum/transaction.py
  5. 12
      electrum/util.py
  6. 8
      electrum/wallet.py

6
electrum/gui/kivy/main_window.py

@ -18,7 +18,7 @@ from electrum.plugin import run_hook
from electrum import util from electrum import util
from electrum.util import (profiler, InvalidPassword, send_exception_to_crash_reporter, from electrum.util import (profiler, InvalidPassword, send_exception_to_crash_reporter,
format_satoshis, format_satoshis_plain, format_fee_satoshis, format_satoshis, format_satoshis_plain, format_fee_satoshis,
maybe_extract_bolt11_invoice) maybe_extract_bolt11_invoice, parse_max_spend)
from electrum.invoices import PR_PAID, PR_FAILED from electrum.invoices import PR_PAID, PR_FAILED
from electrum import blockchain from electrum import blockchain
from electrum.network import Network, TxBroadcastError, BestEffortRequestFailed from electrum.network import Network, TxBroadcastError, BestEffortRequestFailed
@ -988,8 +988,8 @@ class ElectrumWindow(App, Logger):
def format_amount_and_units(self, x) -> str: def format_amount_and_units(self, x) -> str:
if x is None: if x is None:
return 'none' return 'none'
if x == '!': if parse_max_spend(x):
return 'max' return f'max({x})'
# FIXME this is using format_satoshis_plain instead of config.format_amount # FIXME this is using format_satoshis_plain instead of config.format_amount
# as we sometimes convert the returned string back to numbers, # as we sometimes convert the returned string back to numbers,
# via self.get_amount()... the need for converting back should be removed # via self.get_amount()... the need for converting back should be removed

18
electrum/gui/qt/main_window.py

@ -62,7 +62,7 @@ from electrum.util import (format_time,
UserFacingException, UserFacingException,
get_new_wallet_name, send_exception_to_crash_reporter, get_new_wallet_name, send_exception_to_crash_reporter,
InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds, InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
NoDynamicFeeEstimates, MultipleSpendMaxTxOutputs, NoDynamicFeeEstimates,
AddTransactionException, BITCOIN_BIP21_URI_SCHEME, AddTransactionException, BITCOIN_BIP21_URI_SCHEME,
InvoiceError, parse_max_spend) InvoiceError, parse_max_spend)
from electrum.invoices import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING, Invoice from electrum.invoices import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING, Invoice
@ -1351,8 +1351,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.amount_e = BTCAmountEdit(self.get_decimal_point) self.amount_e = BTCAmountEdit(self.get_decimal_point)
self.payto_e = PayToEdit(self) self.payto_e = PayToEdit(self)
self.payto_e.addPasteButton(self.app) self.payto_e.addPasteButton(self.app)
msg = _('Recipient of the funds.') + '\n\n'\ msg = (_("Recipient of the funds.") + "\n\n"
+ _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)') + _("You may enter a Bitcoin address, a label from your list of contacts "
"(a list of completions will be proposed), "
"or an alias (email-like address that forwards to a Bitcoin address)") + ". "
+ _("Lightning invoices are also supported.") + "\n\n"
+ _("You can also pay to many outputs in a single transaction, "
"specifying one output per line.") + "\n" + _("Format: address, amount") + "\n"
+ _("To set the amount to 'max', use the '!' special character.") + "\n"
+ _("Integers weights can also be used in conjunction with '!', "
"e.g. set one amount to '2!' and another to '3!' to split your coins 40-60."))
payto_label = HelpLabel(_('Pay to'), msg) payto_label = HelpLabel(_('Pay to'), msg)
grid.addWidget(payto_label, 1, 0) grid.addWidget(payto_label, 1, 0)
grid.addWidget(self.payto_e, 1, 1, 1, -1) grid.addWidget(self.payto_e, 1, 1, 1, -1)
@ -1451,10 +1459,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
# Check if we had enough funds excluding fees, # Check if we had enough funds excluding fees,
# if so, still provide opportunity to set lower fees. # if so, still provide opportunity to set lower fees.
tx = make_tx(0) tx = make_tx(0)
except MultipleSpendMaxTxOutputs as e:
self.max_button.setChecked(False)
self.show_error(str(e))
return
except NotEnoughFunds as e: except NotEnoughFunds as e:
self.max_button.setChecked(False) self.max_button.setChecked(False)
text = self.get_text_not_enough_funds_mentioning_frozen() text = self.get_text_not_enough_funds_mentioning_frozen()

2
electrum/invoices.py

@ -136,7 +136,7 @@ class OnchainInvoice(Invoice):
if not (0 <= value <= TOTAL_COIN_SUPPLY_LIMIT_IN_BTC * COIN): if not (0 <= value <= TOTAL_COIN_SUPPLY_LIMIT_IN_BTC * COIN):
raise InvoiceError(f"amount is out-of-bounds: {value!r} sat") raise InvoiceError(f"amount is out-of-bounds: {value!r} sat")
elif isinstance(value, str): elif isinstance(value, str):
if value != "!": if value != '!':
raise InvoiceError(f"unexpected amount: {value!r}") raise InvoiceError(f"unexpected amount: {value!r}")
else: else:
raise InvoiceError(f"unexpected amount: {value!r}") raise InvoiceError(f"unexpected amount: {value!r}")

6
electrum/transaction.py

@ -42,7 +42,7 @@ import copy
from . import ecc, bitcoin, constants, segwit_addr, bip32 from . import ecc, bitcoin, constants, segwit_addr, bip32
from .bip32 import BIP32Node from .bip32 import BIP32Node
from .util import profiler, to_bytes, bh2u, bfh, chunks, is_hex_str from .util import profiler, to_bytes, bh2u, bfh, chunks, is_hex_str, parse_max_spend
from .bitcoin import (TYPE_ADDRESS, TYPE_SCRIPT, hash_160, from .bitcoin import (TYPE_ADDRESS, TYPE_SCRIPT, hash_160,
hash160_to_p2sh, hash160_to_p2pkh, hash_to_segwit_addr, hash160_to_p2sh, hash160_to_p2pkh, hash_to_segwit_addr,
var_int, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC, COIN, var_int, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC, COIN,
@ -109,7 +109,9 @@ class TxOutput:
def __init__(self, *, scriptpubkey: bytes, value: Union[int, str]): def __init__(self, *, scriptpubkey: bytes, value: Union[int, str]):
self.scriptpubkey = scriptpubkey self.scriptpubkey = scriptpubkey
self.value = value # str when the output is set to max: '!' # in satoshis if not (isinstance(value, int) or parse_max_spend(value) is not None):
raise ValueError(f"bad txout value: {value!r}")
self.value = value # int in satoshis; or spend-max-like str
@classmethod @classmethod
def from_address_and_value(cls, address: str, value: Union[int, str]) -> Union['TxOutput', 'PartialTxOutput']: def from_address_and_value(cls, address: str, value: Union[int, str]) -> Union['TxOutput', 'PartialTxOutput']:

12
electrum/util.py

@ -111,6 +111,7 @@ def base_unit_name_to_decimal_point(unit_name: str) -> int:
def parse_max_spend(amt: Any) -> Optional[int]: def parse_max_spend(amt: Any) -> Optional[int]:
"""Checks if given amount is "spend-max"-like. """Checks if given amount is "spend-max"-like.
Returns None or the positive integer weight for "max". Never raises. Returns None or the positive integer weight for "max". Never raises.
When creating invoices and on-chain txs, the user can specify to send "max". When creating invoices and on-chain txs, the user can specify to send "max".
This is done by setting the amount to '!'. Splitting max between multiple This is done by setting the amount to '!'. Splitting max between multiple
tx outputs is also possible, and custom weights (positive ints) can also be used. tx outputs is also possible, and custom weights (positive ints) can also be used.
@ -143,11 +144,6 @@ class NoDynamicFeeEstimates(Exception):
return _('Dynamic fee estimates not available') return _('Dynamic fee estimates not available')
class MultipleSpendMaxTxOutputs(Exception):
def __str__(self):
return _('At most one output can be set to spend max')
class InvalidPassword(Exception): class InvalidPassword(Exception):
def __str__(self): def __str__(self):
return _("Incorrect password") return _("Incorrect password")
@ -658,8 +654,8 @@ def format_satoshis_plain(
) -> str: ) -> str:
"""Display a satoshi amount scaled. Always uses a '.' as a decimal """Display a satoshi amount scaled. Always uses a '.' as a decimal
point and has no thousands separator""" point and has no thousands separator"""
if x == '!': if parse_max_spend(x):
return 'max' return f'max({x})'
assert isinstance(x, (int, float, Decimal)), f"{x!r} should be a number" assert isinstance(x, (int, float, Decimal)), f"{x!r} should be a number"
scale_factor = pow(10, decimal_point) scale_factor = pow(10, decimal_point)
return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.') return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.')
@ -688,7 +684,7 @@ def format_satoshis(
if x is None: if x is None:
return 'unknown' return 'unknown'
if parse_max_spend(x): if parse_max_spend(x):
return f'max ({x}) ' return f'max({x})'
assert isinstance(x, (int, float, Decimal)), f"{x!r} should be a number" assert isinstance(x, (int, float, Decimal)), f"{x!r} should be a number"
# lose redundant precision # lose redundant precision
x = Decimal(x).quantize(Decimal(10) ** (-precision)) x = Decimal(x).quantize(Decimal(10) ** (-precision))

8
electrum/wallet.py

@ -54,7 +54,7 @@ from .crypto import sha256
from . import util from . import util
from .util import (NotEnoughFunds, UserCancelled, profiler, from .util import (NotEnoughFunds, UserCancelled, profiler,
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates, format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
WalletFileException, BitcoinException, MultipleSpendMaxTxOutputs, WalletFileException, BitcoinException,
InvalidPassword, format_time, timestamp_to_datetime, Satoshis, InvalidPassword, format_time, timestamp_to_datetime, Satoshis,
Fiat, bfh, bh2u, TxMinedInfo, quantize_feerate, create_bip21_uri, OrderedDictWithIndex, parse_max_spend) Fiat, bfh, bh2u, TxMinedInfo, quantize_feerate, create_bip21_uri, OrderedDictWithIndex, parse_max_spend)
from .simple_config import SimpleConfig, FEE_RATIO_HIGH_WARNING, FEERATE_WARNING_HIGH_FEE from .simple_config import SimpleConfig, FEE_RATIO_HIGH_WARNING, FEERATE_WARNING_HIGH_FEE
@ -1342,7 +1342,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
weight = parse_max_spend(o.value) weight = parse_max_spend(o.value)
if weight: if weight:
i_max_sum += weight i_max_sum += weight
i_max.append((weight,i)) i_max.append((weight, i))
if fee is None and self.config.fee_per_kb() is None: if fee is None and self.config.fee_per_kb() is None:
raise NoDynamicFeeEstimates() raise NoDynamicFeeEstimates()
@ -1412,8 +1412,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC):
if amount < 0: if amount < 0:
raise NotEnoughFunds() raise NotEnoughFunds()
distr_amount = 0 distr_amount = 0
for (x,i) in i_max: for (weight, i) in i_max:
val = int((amount/i_max_sum)*x) val = int((amount/i_max_sum) * weight)
outputs[i].value = val outputs[i].value = val
distr_amount += val distr_amount += val

Loading…
Cancel
Save