tx.new: user fee, fee estimate cleanups
This commit is contained in:
parent
e42c404d9d
commit
dece143f9b
3 changed files with 39 additions and 38 deletions
|
|
@ -37,19 +37,30 @@ class New(Base,TxBase.New):
|
|||
pink(str(self.cfg.fee_estimate_confs)),
|
||||
suf(self.cfg.fee_estimate_confs))
|
||||
|
||||
def warn_fee_estimate_fail(self, fe_type):
|
||||
if not hasattr(self, '_fee_estimate_fail_warning_shown'):
|
||||
msg(self.fee_fail_fs.format(
|
||||
c = self.cfg.fee_estimate_confs,
|
||||
t = fe_type))
|
||||
self._fee_estimate_fail_warning_shown = True
|
||||
|
||||
async def get_rel_fee_from_network(self):
|
||||
try:
|
||||
ret = await self.rpc.call(
|
||||
'estimatesmartfee',
|
||||
self.cfg.fee_estimate_confs,
|
||||
self.cfg.fee_estimate_mode.upper() )
|
||||
fee_per_kb = ret['feerate'] if 'feerate' in ret else -2
|
||||
self.cfg.fee_estimate_mode.upper())
|
||||
fee_per_kb = self.proto.coin_amt(ret['feerate']) if 'feerate' in ret else None
|
||||
fe_type = 'estimatesmartfee'
|
||||
except:
|
||||
args = self.rpc.daemon.estimatefee_args(self.rpc)
|
||||
fee_per_kb = await self.rpc.call('estimatefee', *args)
|
||||
ret = await self.rpc.call('estimatefee', *args)
|
||||
fee_per_kb = self.proto.coin_amt(ret)
|
||||
fe_type = 'estimatefee'
|
||||
|
||||
if fee_per_kb is None:
|
||||
self.warn_fee_estimate_fail(fe_type)
|
||||
|
||||
return fee_per_kb, fe_type
|
||||
|
||||
# given tx size, rel fee and units, return absolute fee
|
||||
|
|
@ -64,9 +75,7 @@ class New(Base,TxBase.New):
|
|||
def fee_est2abs(self,fee_per_kb,fe_type=None):
|
||||
from decimal import Decimal
|
||||
tx_size = self.estimate_size()
|
||||
ret = self.proto.coin_amt(
|
||||
fee_per_kb * Decimal(self.cfg.fee_adjust) * tx_size / 1024,
|
||||
from_decimal = True)
|
||||
ret = self.proto.coin_amt('1') * (fee_per_kb * self.cfg.fee_adjust * tx_size / 1024)
|
||||
if self.cfg.verbose:
|
||||
msg(fmt(f"""
|
||||
{fe_type.upper()} fee for {self.cfg.fee_estimate_confs} confirmations: {fee_per_kb} {self.coin}/kB
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class New(Base,TxBase.New):
|
|||
fee_fail_fs = 'Network fee estimation failed'
|
||||
no_chg_msg = 'Warning: Transaction leaves account with zero balance'
|
||||
usr_fee_prompt = 'Enter transaction fee or gas price: '
|
||||
msg_insufficient_funds = 'Account balance insufficient to fund this transaction ({} {} needed)'
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
||||
|
|
@ -207,7 +208,8 @@ class TokenNew(TokenBase,New):
|
|||
return await super().precheck_sufficient_funds(inputs_sum,sel_unspent,outputs_sum)
|
||||
|
||||
async def get_funds_available(self, fee, outputs_sum):
|
||||
return (await self.twctl.get_eth_balance(self.inputs[0].addr)) - fee
|
||||
bal = await self.twctl.get_eth_balance(self.inputs[0].addr)
|
||||
return self._funds_available(bal >= fee, bal - fee if bal >= fee else fee - bal)
|
||||
|
||||
def final_inputs_ok_msg(self,funds_left):
|
||||
token_bal = (
|
||||
|
|
|
|||
|
|
@ -73,13 +73,17 @@ def mmaddr2coinaddr(cfg, mmaddr, ad_w, ad_f, proto):
|
|||
class New(Base):
|
||||
|
||||
fee_is_approximate = False
|
||||
msg_low_coin = 'Selected outputs insufficient to fund this transaction ({} {} needed)'
|
||||
msg_wallet_low_coin = 'Wallet has insufficient funds for this transaction ({} {} needed)'
|
||||
msg_no_change_output = """
|
||||
ERROR: No change address specified. If you wish to create a transaction with
|
||||
only one output, specify a single output address with no {} amount
|
||||
"""
|
||||
msg_insufficient_funds = 'Selected outputs insufficient to fund this transaction ({} {} needed)'
|
||||
chg_autoselected = False
|
||||
_funds_available = namedtuple('funds_available', ['is_positive', 'amt'])
|
||||
|
||||
def warn_insufficient_funds(self, amt, coin):
|
||||
msg(self.msg_insufficient_funds.format(amt.hl(), coin))
|
||||
|
||||
def update_output_amt(self, idx, amt):
|
||||
o = self.outputs[idx]._asdict()
|
||||
|
|
@ -149,29 +153,10 @@ class New(Base):
|
|||
msg(self.msg_wallet_low_coin.format(outputs_sum-inputs_sum, self.dcoin))
|
||||
return False
|
||||
if inputs_sum < outputs_sum:
|
||||
msg(self.msg_low_coin.format(outputs_sum-inputs_sum, self.dcoin))
|
||||
self.warn_insufficient_funds(outputs_sum - inputs_sum, self.dcoin)
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_fee_from_user(self, have_estimate_fail=[]):
|
||||
|
||||
if self.cfg.fee:
|
||||
desc = 'User-selected'
|
||||
start_fee = self.cfg.fee
|
||||
else:
|
||||
desc = self.network_estimated_fee_label
|
||||
fee_per_kb, fe_type = await self.get_rel_fee_from_network()
|
||||
|
||||
if fee_per_kb < 0:
|
||||
if not have_estimate_fail:
|
||||
msg(self.fee_fail_fs.format(c=self.cfg.fee_estimate_confs, t=fe_type))
|
||||
have_estimate_fail.append(True)
|
||||
start_fee = None
|
||||
else:
|
||||
start_fee = self.fee_est2abs(fee_per_kb, fe_type)
|
||||
|
||||
return self.get_usr_fee_interactive(start_fee, desc=desc)
|
||||
|
||||
def add_output(self, coinaddr, amt, is_chg=None):
|
||||
self.outputs.append(self.Output(self.proto, addr=coinaddr, amt=amt, is_chg=is_chg))
|
||||
|
||||
|
|
@ -358,11 +343,10 @@ class New(Base):
|
|||
yield i
|
||||
self.inputs = type(self.inputs)(self, list(gen_inputs()))
|
||||
|
||||
def warn_insufficient_funds(self, funds_left):
|
||||
msg(self.msg_low_coin.format(self.proto.coin_amt(-funds_left).hl(), self.coin))
|
||||
|
||||
async def get_funds_available(self, fee, outputs_sum):
|
||||
return self.sum_inputs() - outputs_sum - fee
|
||||
in_ = self.sum_inputs()
|
||||
out = outputs_sum + fee
|
||||
return self._funds_available(in_ >= out, in_ - out if in_ >= out else out - in_)
|
||||
|
||||
async def get_inputs_from_user(self, outputs_sum):
|
||||
|
||||
|
|
@ -379,19 +363,25 @@ class New(Base):
|
|||
|
||||
self.copy_inputs_from_tw(sel_unspent) # makes self.inputs
|
||||
|
||||
self.usr_fee = await self.get_fee_from_user()
|
||||
if self.cfg.fee:
|
||||
self.usr_fee = self.get_usr_fee_interactive(self.cfg.fee, 'User-selected')
|
||||
else:
|
||||
fee_per_kb, fe_type = await self.get_rel_fee_from_network()
|
||||
self.usr_fee = self.get_usr_fee_interactive(
|
||||
None if fee_per_kb is None else self.fee_est2abs(fee_per_kb, fe_type),
|
||||
self.network_estimated_fee_label)
|
||||
|
||||
funds_left = await self.get_funds_available(self.usr_fee,outputs_sum)
|
||||
funds = await self.get_funds_available(self.usr_fee, outputs_sum)
|
||||
|
||||
if funds_left >= 0:
|
||||
p = self.final_inputs_ok_msg(funds_left)
|
||||
if funds.is_positive:
|
||||
p = self.final_inputs_ok_msg(funds.amt)
|
||||
from ..ui import keypress_confirm
|
||||
if self.cfg.yes or keypress_confirm(self.cfg, p+'. OK?', default_yes=True):
|
||||
if self.cfg.yes:
|
||||
msg(p)
|
||||
return funds_left
|
||||
return funds.amt
|
||||
else:
|
||||
self.warn_insufficient_funds(funds_left)
|
||||
self.warn_insufficient_funds(funds.amt, self.coin)
|
||||
|
||||
async def create(self, cmd_args, locktime=None, do_info=False, caller='txcreate'):
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue