rune: support user-specified transaction fees
This commit is contained in:
parent
dc7f256270
commit
384384c260
13 changed files with 48 additions and 19 deletions
|
|
@ -193,7 +193,7 @@ class BTCAmt(CoinAmt):
|
|||
max_amt = 21000000
|
||||
satoshi = Decimal('0.00000001')
|
||||
atomic = satoshi
|
||||
units = ('satoshi',)
|
||||
units = ('atomic', 'satoshi')
|
||||
|
||||
class UniAmt(BTCAmt):
|
||||
coin = None
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@
|
|||
## rpc_host btc ltc bch eth etc ##
|
||||
## rpc_port btc ltc bch eth etc xmr ##
|
||||
## ignore_daemon_version btc ltc bch eth etc xmr ##
|
||||
## max_tx_fee btc ltc bch eth etc ##
|
||||
## max_tx_fee btc ltc bch eth etc rune ##
|
||||
## Note: prefix is followed by an underscore, e.g. ‘xmr_rpc_port’ ##
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
|
@ -154,6 +154,9 @@
|
|||
# Set the maximum transaction fee for ETH:
|
||||
# eth_max_tx_fee 0.005
|
||||
|
||||
# Set the maximum transaction fee for RUNE:
|
||||
# rune_max_tx_fee 0.2
|
||||
|
||||
# Set the Ethereum mainnet chain names (space-separated list, first is default):
|
||||
# eth_mainnet_chain_names ethereum foundation
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ opts_data = {
|
|||
e- -D, --contract-data=D Path to file containing hex-encoded contract data
|
||||
b- -E, --fee-estimate-mode=M Specify the network fee estimate mode. Choices:
|
||||
+ {fe_all}. Default: {fe_dfl!r}
|
||||
X- -f, --fee= f Transaction fee, as a decimal {cu} amount
|
||||
R- -f, --fee= f Transaction fee, as a decimal {cu} amount or as
|
||||
+ {fu} (an integer followed by {fl}).
|
||||
+ See FEE SPECIFICATION below. If omitted, fee will be
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class mainnet(CoinProtocol.Secp256k1):
|
|||
preferred_mmtypes = ('X',)
|
||||
dfl_mmtype = 'X'
|
||||
coin_amt = 'UniAmt'
|
||||
max_tx_fee = 0.1
|
||||
max_tx_fee = 0.2
|
||||
caps = ()
|
||||
mmcaps = ('tw', 'rpc', 'rpc_init')
|
||||
base_proto = 'THORChain'
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ class Base(TxBase):
|
|||
def nondata_outputs(self):
|
||||
return self.outputs
|
||||
|
||||
@property
|
||||
def usr_fee(self):
|
||||
return self.proto.coin_amt(self.dfl_fee, from_unit='satoshi')
|
||||
|
||||
def add_blockcount(self):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ class Completed(VmCompleted, Base, TxBase.Completed):
|
|||
|
||||
@property
|
||||
def fee(self):
|
||||
return self.proto.coin_amt(self.dfl_fee, from_unit='satoshi')
|
||||
return self.txobj['fee'] if self.txobj['fee'] else self.proto.coin_amt('0')
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ proto.rune.tx.info: THORChain transaction info class
|
|||
"""
|
||||
|
||||
from ....tx.info import TxInfo
|
||||
from ....color import pink
|
||||
from ....color import blue, pink
|
||||
from ....obj import NonNegativeInt
|
||||
|
||||
from ...vm.tx.info import VmTxInfo, mmid_disp
|
||||
|
|
@ -27,6 +27,7 @@ class TxInfo(VmTxInfo, TxInfo):
|
|||
fs = """
|
||||
From: {f}{f_mmid}
|
||||
Amount: {a} {c}
|
||||
Fee: {F} {C}
|
||||
Gas limit: {G}
|
||||
Sequence: {N}
|
||||
Memo: {m}
|
||||
|
|
@ -34,6 +35,7 @@ class TxInfo(VmTxInfo, TxInfo):
|
|||
From: {f}{f_mmid}
|
||||
To: {t}{t_mmid}
|
||||
Amount: {a} {c}
|
||||
Fee: {F} {C}
|
||||
Gas limit: {G}
|
||||
Sequence: {N}
|
||||
"""
|
||||
|
|
@ -41,9 +43,11 @@ class TxInfo(VmTxInfo, TxInfo):
|
|||
f = t['from'].hl(0),
|
||||
t = None if has_memo else t['to'].hl(0),
|
||||
a = t['amt'].hl(),
|
||||
F = blue('None') if t['fee'] is None else t['fee'].hl(),
|
||||
N = NonNegativeInt(t['sequence']).hl(),
|
||||
m = pink(tx.swap_memo) if has_memo else None,
|
||||
c = tx.proto.dcoin if tx.outputs else '',
|
||||
C = tx.proto.dcoin,
|
||||
G = NonNegativeInt(tx.total_gas).hl(),
|
||||
f_mmid = mmid_disp(tx.inputs[0], nonmm_str),
|
||||
t_mmid = None if has_memo else mmid_disp(tx.outputs[0], nonmm_str)) + '\n\n'
|
||||
|
|
|
|||
|
|
@ -20,8 +20,13 @@ from .base import Base
|
|||
|
||||
class New(VmNew, Base, TxBase.New):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.usr_fee = None if self.cfg.fee is None else self.proto.coin_amt(self.cfg.fee)
|
||||
|
||||
async def get_funds_remaining(self, fee, outputs_sum, start_fee_desc):
|
||||
return await self.twctl.get_balance(self.inputs[0].addr)
|
||||
res = await self.twctl.get_balance(self.inputs[0].addr)
|
||||
return (res - self.usr_fee) if self.usr_fee else res
|
||||
|
||||
async def set_gas(self, *, to_addr=None, force=False):
|
||||
self.gas = self.dfl_gas
|
||||
|
|
@ -40,6 +45,7 @@ class New(VmNew, Base, TxBase.New):
|
|||
'from': self.inputs[0].addr,
|
||||
'to': self.outputs[0].addr if self.outputs else None,
|
||||
'amt': self.sum_outputs(),
|
||||
'fee': self.usr_fee,
|
||||
'gas': self.gas,
|
||||
'account_number': int(acct_info['account_number']),
|
||||
'sequence': int(acct_info['sequence']),
|
||||
|
|
|
|||
|
|
@ -44,10 +44,11 @@ send_tx_parms = namedtuple(
|
|||
'gas_limit',
|
||||
'account_number',
|
||||
'sequence',
|
||||
'fee', # begin default fields
|
||||
'pubkey',
|
||||
'wifkey',
|
||||
'signature'],
|
||||
defaults = (None, None, None))
|
||||
defaults = (0, None, None, None))
|
||||
|
||||
deposit_tx_parms = namedtuple(
|
||||
'rune_deposit_tx_parms', [
|
||||
|
|
@ -61,13 +62,14 @@ deposit_tx_parms = namedtuple(
|
|||
'sequence',
|
||||
'decimals',
|
||||
'memo',
|
||||
'synth', # begin default fields
|
||||
'fee', # begin default fields
|
||||
'synth',
|
||||
'trade',
|
||||
'secured',
|
||||
'pubkey',
|
||||
'wifkey',
|
||||
'signature'],
|
||||
defaults = (None, None, None, None, None, None))
|
||||
defaults = (0, None, None, None, None, None, None))
|
||||
|
||||
# subset of deposit_tx_parms:
|
||||
swap_tx_parms = namedtuple(
|
||||
|
|
@ -78,13 +80,14 @@ swap_tx_parms = namedtuple(
|
|||
'account_number',
|
||||
'sequence',
|
||||
'memo',
|
||||
'synth', # begin default fields
|
||||
'fee', # begin default fields
|
||||
'synth',
|
||||
'trade',
|
||||
'secured',
|
||||
'pubkey',
|
||||
'wifkey',
|
||||
'signature'],
|
||||
defaults = (None, None, None, None, None, None))
|
||||
defaults = (0, None, None, None, None, None, None))
|
||||
|
||||
@dataclass
|
||||
class Asset(BaseMessage):
|
||||
|
|
@ -158,9 +161,16 @@ def amt_to_base_unit(amt, *, decimals):
|
|||
def base_unit_to_amt(n, *, decimals):
|
||||
return n * Decimal(10) ** -decimals
|
||||
|
||||
def parse_fee(proto, tx, color=None):
|
||||
if (fee := tx.authInfo.fee.amount) is None:
|
||||
return None
|
||||
else:
|
||||
return proto.coin_amt(int(fee[0].amount), from_unit='atomic')
|
||||
|
||||
def tx_info(tx, proto):
|
||||
b = tx.body.messages[0].body
|
||||
s = tx.authInfo.signerInfos[0]
|
||||
fee = parse_fee(proto, tx)
|
||||
match msg_type := tx.body.messages[0].id.removeprefix('/types.'):
|
||||
case 'MsgSend':
|
||||
from_addr = proto.encode_addr_bech32x(b.fromAddress)
|
||||
|
|
@ -180,6 +190,7 @@ def tx_info(tx, proto):
|
|||
yield f'To: {to_addr}'
|
||||
yield f'Asset: {asset}'
|
||||
yield f'Amount: {amt}'
|
||||
yield f'Fee: {None if fee is None else fee.hl(color=None)}'
|
||||
yield f'Sequence: {int(s.sequence)}'
|
||||
yield f'Gas limit: {tx.authInfo.fee.gasLimit}'
|
||||
yield f'Memo: {memo}'
|
||||
|
|
@ -203,6 +214,7 @@ def build_swap_tx(cfg, proto, parms, *, skip_body_memo=False):
|
|||
account_number = p.account_number,
|
||||
sequence = p.sequence,
|
||||
decimals = 8,
|
||||
fee = p.fee,
|
||||
synth = p.synth,
|
||||
trade = p.trade,
|
||||
secured = p.secured,
|
||||
|
|
@ -256,7 +268,7 @@ def build_tx(cfg, proto, parms, *, null_fee=False, skip_body_memo=False):
|
|||
coins = [coin_data],
|
||||
memo = p.memo,
|
||||
signer = proto.decode_addr(p.from_addr).bytes))
|
||||
fee_amt = None if null_fee else [Coin(denom='rune', amount='0')]
|
||||
fee_amt = None if null_fee else [Coin(denom='rune', amount=str(p.fee))]
|
||||
|
||||
signer_info = SignerInfo(
|
||||
publicKey = PublicKey(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class Signed(Completed, TxBase.Signed):
|
|||
desc = 'signed transaction'
|
||||
|
||||
def parse_txfile_serialized_data(self):
|
||||
from .protobuf import RuneTx
|
||||
from .protobuf import RuneTx, parse_fee
|
||||
tx = RuneTx.loads(bytes.fromhex(self.serialized))
|
||||
|
||||
b = tx.body.messages[0].body
|
||||
|
|
@ -33,6 +33,7 @@ class Signed(Completed, TxBase.Signed):
|
|||
'from': self.proto.encode_addr_bech32x(getattr(b, from_k)),
|
||||
'to': None if self.is_swap else self.proto.encode_addr_bech32x(b.toAddress),
|
||||
'amt': self.proto.coin_amt(int(getattr(b, amt_k)[0].amount), from_unit='satoshi'),
|
||||
'fee': parse_fee(self.proto, tx),
|
||||
'gas': NonNegativeInt(i.fee.gasLimit),
|
||||
'sequence': NonNegativeInt(i.signerInfos[0].sequence)}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class Unsigned(VmUnsigned, Completed, TxBase.Unsigned):
|
|||
'from': CoinAddr(self.proto, d['from']),
|
||||
'to': CoinAddr(self.proto, d['to']) if d['to'] else None,
|
||||
'amt': self.proto.coin_amt(d['amt']),
|
||||
'fee': None if d['fee'] is None else self.proto.coin_amt(d['fee']),
|
||||
'gas': NonNegativeInt(d['gas']),
|
||||
'account_number': NonNegativeInt(d['account_number']),
|
||||
'sequence': NonNegativeInt(d['sequence']),
|
||||
|
|
@ -43,6 +44,7 @@ class Unsigned(VmUnsigned, Completed, TxBase.Unsigned):
|
|||
o['account_number'],
|
||||
o['sequence'],
|
||||
self.swap_memo,
|
||||
fee = 0 if o['fee'] is None else o['fee'].to_unit('atomic'),
|
||||
wifkey = wif)
|
||||
else:
|
||||
from .protobuf import send_tx_parms, build_tx
|
||||
|
|
@ -53,6 +55,7 @@ class Unsigned(VmUnsigned, Completed, TxBase.Unsigned):
|
|||
o['gas'],
|
||||
o['account_number'],
|
||||
o['sequence'],
|
||||
fee = 0 if o['fee'] is None else o['fee'].to_unit('atomic'),
|
||||
wifkey = wif)
|
||||
|
||||
tx = build_tx(self.cfg, self.proto, parms)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ class New:
|
|||
|
||||
def check_fee(self):
|
||||
if not self.disable_fee_check:
|
||||
assert self.usr_fee <= self.proto.max_tx_fee
|
||||
if self.usr_fee and self.usr_fee > self.proto.max_tx_fee:
|
||||
die('MaxFeeExceeded', f'{self.usr_fee} > max fee ({self.proto.max_tx_fee})')
|
||||
|
||||
@property
|
||||
def total_gas(self):
|
||||
|
|
|
|||
|
|
@ -139,8 +139,10 @@ class CmdTestRune(CmdTestRuneMethods, CmdTestEthdevMethods, CmdTestBase, CmdTest
|
|||
def twview(self):
|
||||
return self.spawn('mmgen-tool', self.rune_opts + self.add_eth_opts + ['twview'])
|
||||
|
||||
def txcreate1(self):
|
||||
return self._rune_txcreate(add_opts=['--fee=0.2'])
|
||||
|
||||
bal_refresh = CmdTestRuneMethods._rune_bal_refresh
|
||||
txcreate1 = CmdTestRuneMethods._rune_txcreate
|
||||
txsign1 = CmdTestRuneMethods._rune_txsign
|
||||
_txsend = CmdTestRuneMethods._rune_txsend
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue