tx.new_swap: add network-estimated fee display; related cleanups

This commit is contained in:
The MMGen Project 2025-03-21 09:39:38 +03:00
commit ed77c9661e
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
6 changed files with 34 additions and 17 deletions

View file

@ -54,6 +54,9 @@ class New(Base, TxNew):
t = fe_type))
self._fee_estimate_fail_warning_shown = True
def network_fee_to_unit_disp(self, net_fee):
return '{} sat/byte'.format(net_fee.fee.to_unit('satoshi') // 1024)
async def get_rel_fee_from_network(self):
try:
ret = await self.rpc.call(
@ -71,22 +74,22 @@ class New(Base, TxNew):
if fee_per_kb is None:
self.warn_fee_estimate_fail(fe_type)
return fee_per_kb, fe_type
return self._net_fee(fee_per_kb, fe_type)
# given tx size, rel fee and units, return absolute fee
def fee_rel2abs(self, tx_size, amt_in_units, unit):
return self.proto.coin_amt(int(amt_in_units * tx_size), from_unit=unit)
# given network fee estimate in BTC/kB, return absolute fee using estimated tx size
def fee_est2abs(self, fee_per_kb, *, fe_type=None):
def fee_est2abs(self, net_fee):
tx_size = self.estimate_size()
ret = self.proto.coin_amt('1') * (fee_per_kb * self.cfg.fee_adjust * tx_size / 1024)
ret = self.proto.coin_amt('1') * (net_fee.fee * 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
{net_fee.type.upper()} fee for {self.cfg.fee_estimate_confs} confirmations: {net_fee.fee} {self.coin}/kB
TX size (estimated): {tx_size} bytes
Fee adjustment factor: {self.cfg.fee_adjust:.2f}
Absolute fee (fee_per_kb * adj_factor * tx_size / 1024): {ret} {self.coin}
Absolute fee (net_fee.fee * adj_factor * tx_size / 1024): {ret} {self.coin}
""").strip())
return ret

View file

@ -115,9 +115,15 @@ class New(Base, TxBase.New):
def network_estimated_fee_label(self):
return 'Network-estimated'
def network_fee_to_unit_disp(self, net_fee):
return '{} Gwei'.format(self.pretty_fmt_fee(
self.proto.coin_amt(net_fee.fee, from_unit='wei').to_unit('Gwei')))
# get rel_fee (gas price) from network, return in native wei
async def get_rel_fee_from_network(self):
return Int(await self.rpc.call('eth_gasPrice'), base=16), 'eth_gasPrice'
return self._net_fee(
Int(await self.rpc.call('eth_gasPrice'), base=16),
'eth_gasPrice')
def check_chg_addr_is_wallet_addr(self):
pass
@ -131,10 +137,10 @@ class New(Base, TxBase.New):
return self.proto.coin_amt(int(amt_in_units * self.gas.toWei()), from_unit=unit)
# given fee estimate (gas price) in wei, return absolute fee, adjusting by self.cfg.fee_adjust
def fee_est2abs(self, rel_fee, *, fe_type=None):
ret = self.fee_gasPrice2abs(rel_fee) * self.cfg.fee_adjust
def fee_est2abs(self, net_fee):
ret = self.fee_gasPrice2abs(net_fee.fee) * self.cfg.fee_adjust
if self.cfg.verbose:
msg(f'Estimated fee: {ret} ETH')
msg(f'Estimated fee: {net_fee.fee} ETH')
return ret
def convert_and_check_fee(self, fee, desc):

View file

@ -70,7 +70,7 @@ class Thornode:
from ....util import pp_fmt, die
die(2, pp_fmt(self.data))
def format_quote(self, trade_limit, usr_trade_limit, *, deduct_est_fee=False):
async def format_quote(self, trade_limit, usr_trade_limit, *, deduct_est_fee=False):
from ....util import make_timestr, ymsg
from ....util2 import format_elapsed_hr
from ....color import blue, green, cyan, pink, orange, redbg, yelbg, grnbg
@ -137,6 +137,7 @@ class Thornode:
Reverse rate: {(in_amt / out_amt).hl()} {in_coin}/{out_coin}
Recommended minimum in amount: {min_in_amt.hl()} {in_coin}
Recommended fee: {pink(d['recommended_gas_rate'])} {pink(gas_unit_disp)}
Network-estimated fee: {await self.tx.network_fee_disp()} (from node)
Fees:
Total: {fees_t.hl()} {out_coin} ({pink(fees_pct_disp)})
Slippage: {pink(slip_pct_disp)}

View file

@ -86,7 +86,7 @@ class Bump(Completed, NewSwap):
if self.is_swap:
self.recv_proto = self.check_swap_memo().proto
self.process_swap_options()
fee_hint = self.update_vault_output(self.send_amt)
fee_hint = await self.update_vault_output(self.send_amt)
else:
fee_hint = None

View file

@ -87,6 +87,7 @@ class New(Base):
"""
chg_autoselected = False
_funds_available = namedtuple('funds_available', ['is_positive', 'amt'])
_net_fee = namedtuple('network_fee_estimate', ['fee', 'type'])
def warn_insufficient_funds(self, amt, coin):
msg(self.msg_insufficient_funds.format(amt.hl(), coin))
@ -402,14 +403,20 @@ class New(Base):
self.copy_inputs_from_tw(sel_unspent) # makes self.inputs
return True
async def network_fee_disp(self):
res = await self.get_rel_fee_from_network()
return pink(
'N/A' if res.fee is None else
self.network_fee_to_unit_disp(res))
async def get_fee(self, fee, outputs_sum, start_fee_desc):
if fee:
self.usr_fee = self.get_usr_fee_interactive(fee, desc=start_fee_desc)
else:
fee_per_kb, fe_type = await self.get_rel_fee_from_network()
res = 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=fe_type),
None if res.fee is None else self.fee_est2abs(res),
desc = self.network_estimated_fee_label)
funds = await self.get_funds_available(self.usr_fee, outputs_sum)
@ -486,7 +493,7 @@ class New(Base):
continue
fee_hint = None
if self.is_swap:
fee_hint = self.update_vault_output(
fee_hint = await self.update_vault_output(
self.vault_output.amt or self.sum_inputs(),
deduct_est_fee = self.vault_output == self.chg_output)
desc = 'User-selected' if self.cfg.fee else 'Recommended' if fee_hint else None
@ -506,7 +513,7 @@ class New(Base):
self.add_comment() # edits an existing comment
if self.is_swap:
self.update_vault_output(self.vault_output.amt)
await self.update_vault_output(self.vault_output.amt)
await self.create_serialized(locktime=locktime) # creates self.txid too

View file

@ -162,7 +162,7 @@ class NewSwap(New):
o['addr'] = addr
self.outputs[vault_idx] = self.Output(self.proto, **o)
def update_vault_output(self, amt, *, deduct_est_fee=False):
async def update_vault_output(self, amt, *, deduct_est_fee=False):
sp = get_swap_proto_mod(self.swap_proto)
c = sp.rpc_client(self, amt)
@ -182,7 +182,7 @@ class NewSwap(New):
c.get_quote()
trade_limit = get_trade_limit()
self.cfg._util.qmsg('OK')
msg(c.format_quote(trade_limit, self.usr_trade_limit, deduct_est_fee=deduct_est_fee))
msg(await c.format_quote(trade_limit, self.usr_trade_limit, deduct_est_fee=deduct_est_fee))
ch = get_char('Press ‘r’ to refresh quote, any other key to continue: ')
msg('')
if ch not in 'Rr':