swaptxcreate: add --router-gas option; proto.eth.tx: new total_gas attr
This commit is contained in:
parent
8d33c6d4a9
commit
aaaccc6bad
11 changed files with 49 additions and 13 deletions
|
|
@ -59,6 +59,8 @@ opts_data = {
|
|||
+ calculated using network fee estimation.
|
||||
et -g, --gas=N Specify gas limit (integer)
|
||||
-s -g, --gas=N Specify gas limit for Ethereum (integer)
|
||||
-s -G, --router-gas=N Specify gas limit for Ethereum router contract
|
||||
+ (integer). Applicable only for swaps from token assets
|
||||
-- -i, --info Display {a_info} and exit
|
||||
-- -I, --inputs= i Specify transaction inputs (comma-separated list of
|
||||
+ MMGen IDs or coin addresses). Note that ALL unspent
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ opts_data = {
|
|||
+ calculated using network fee estimation.
|
||||
et -g, --gas=N Specify gas limit (integer)
|
||||
-s -g, --gas=N Specify gas limit for Ethereum (integer)
|
||||
-s -G, --router-gas=N Specify gas limit for Ethereum router contract
|
||||
+ (integer). Applicable only for swaps from token assets
|
||||
-- -H, --hidden-incog-input-params=f,o Read hidden incognito data from file
|
||||
+ 'f' at offset 'o' (comma-separated)
|
||||
-- -i, --in-fmt= f Input is from wallet format 'f' (see FMT CODES below)
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ class Base(TxBase):
|
|||
|
||||
# given absolute fee in ETH, return gas price in ETH
|
||||
def fee_abs2gasprice(self, abs_fee):
|
||||
return self.proto.coin_amt(int(abs_fee.toWei() // self.gas), from_unit='wei')
|
||||
return self.proto.coin_amt(int(abs_fee.toWei() // self.total_gas), from_unit='wei')
|
||||
|
||||
# given rel fee (gasPrice) in wei, return absolute fee using self.gas (Ethereum-only method)
|
||||
# given rel fee (gasPrice) in wei, return absolute fee using self.total_gas
|
||||
def fee_gasPrice2abs(self, rel_fee):
|
||||
assert isinstance(rel_fee, int), f'{rel_fee!r}: incorrect type for fee estimate (not an integer)'
|
||||
return self.proto.coin_amt(rel_fee * self.gas, from_unit='wei')
|
||||
return self.proto.coin_amt(rel_fee * self.total_gas, from_unit='wei')
|
||||
|
||||
def is_replaceable(self):
|
||||
return True
|
||||
|
|
@ -112,6 +112,7 @@ class Base(TxBase):
|
|||
|
||||
class TokenBase(Base):
|
||||
dfl_gas = 75000
|
||||
dfl_router_gas = 150000
|
||||
contract_desc = 'token contract'
|
||||
|
||||
def check_serialized_integrity(self):
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ class Completed(Base, TxBase.Completed):
|
|||
def send_amt(self):
|
||||
return self.outputs[0].amt if self.outputs else self.proto.coin_amt('0')
|
||||
|
||||
@property
|
||||
def total_gas(self):
|
||||
return self.txobj['startGas']
|
||||
|
||||
@property
|
||||
def fee(self):
|
||||
return self.fee_gasPrice2abs(self.txobj['gasPrice'].toWei())
|
||||
|
|
@ -53,3 +57,7 @@ class TokenCompleted(TokenBase, Completed):
|
|||
@property
|
||||
def change(self):
|
||||
return self.sum_inputs() - self.send_amt
|
||||
|
||||
@property
|
||||
def total_gas(self):
|
||||
return self.txobj['startGas'] + (self.txobj['router_gas'] if self.is_swap else 0)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ proto.eth.tx.info: Ethereum transaction info class
|
|||
|
||||
from ....tx.info import TxInfo
|
||||
from ....util import fmt, pp_fmt
|
||||
from ....color import yellow, blue, cyan, pink
|
||||
from ....color import red, yellow, blue, cyan, pink
|
||||
from ....addr import MMGenID
|
||||
from ....obj import Int
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ class TxInfo(TxInfo):
|
|||
{toaddr} {t}{t_mmid}{tvault}
|
||||
Amount: {a} {c}
|
||||
Gas price: {g} Gwei
|
||||
Gas limit: {G}
|
||||
Gas limit: {G}{G_dec}
|
||||
Nonce: {n}
|
||||
Data: {d}
|
||||
""".strip().replace('\t', '') + ('\nMemo: {m}' if tx.is_swap else '')
|
||||
|
|
@ -57,7 +57,8 @@ class TxInfo(TxInfo):
|
|||
m = pink(tx.swap_memo) if tx.is_swap else None,
|
||||
c = tx.proto.dcoin if len(tx.outputs) else '',
|
||||
g = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
|
||||
G = Int(t['startGas']).hl(),
|
||||
G = Int(tx.total_gas).hl(),
|
||||
G_dec = red(f" ({t['startGas']} + {t['router_gas']})") if tokenswap else '',
|
||||
f_mmid = mmid_disp(tx.inputs[0]),
|
||||
t_mmid = mmid_disp(tx.outputs[0]) if tx.outputs and not tx.is_swap else '') + '\n\n'
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ class New(Base, TxBase.New):
|
|||
|
||||
self.gas = int(self.cfg.gas or self.dfl_gas)
|
||||
|
||||
if self.is_token and self.is_swap:
|
||||
self.router_gas = int(self.cfg.router_gas or self.dfl_router_gas)
|
||||
|
||||
if self.cfg.contract_data:
|
||||
m = "'--contract-data' option may not be used with token transaction"
|
||||
assert 'Token' not in self.name, m
|
||||
|
|
@ -149,9 +152,13 @@ class New(Base, TxBase.New):
|
|||
if not self.disable_fee_check:
|
||||
assert self.usr_fee <= self.proto.max_tx_fee
|
||||
|
||||
# given rel fee and units, return absolute fee using self.gas
|
||||
@property
|
||||
def total_gas(self):
|
||||
return self.gas
|
||||
|
||||
# given rel fee and units, return absolute fee using self.total_gas
|
||||
def fee_rel2abs(self, tx_size, amt_in_units, unit):
|
||||
return self.proto.coin_amt(int(amt_in_units * self.gas), from_unit=unit)
|
||||
return self.proto.coin_amt(int(amt_in_units * self.total_gas), from_unit=unit)
|
||||
|
||||
# given fee estimate (gas price) in wei, return absolute fee, adjusting by self.cfg.fee_adjust
|
||||
def fee_est2abs(self, net_fee):
|
||||
|
|
@ -207,6 +214,10 @@ class TokenNew(TokenBase, New):
|
|||
desc = 'transaction'
|
||||
fee_is_approximate = True
|
||||
|
||||
@property
|
||||
def total_gas(self):
|
||||
return self.gas + (self.router_gas if self.is_swap else 0)
|
||||
|
||||
async def make_txobj(self): # called by create_serialized()
|
||||
await super().make_txobj()
|
||||
t = Token(self.cfg, self.proto, self.twctl.token, decimals=self.twctl.decimals)
|
||||
|
|
@ -216,6 +227,7 @@ class TokenNew(TokenBase, New):
|
|||
o['token_to'] = o['to']
|
||||
if self.is_swap:
|
||||
o['expiry'] = self.quote_data.data['expiry']
|
||||
o['router_gas'] = self.router_gas
|
||||
|
||||
def update_change_output(self, funds_left):
|
||||
if self.outputs[0].is_chg:
|
||||
|
|
|
|||
|
|
@ -79,6 +79,12 @@ class TokenOnlineSigned(TokenSigned, OnlineSigned):
|
|||
t = Token(self.cfg, self.proto, o['token_addr'], decimals=o['decimals'])
|
||||
o['amt'] = t.transferdata2amt(o['data'])
|
||||
o['token_to'] = t.transferdata2sendaddr(o['data'])
|
||||
if self.is_swap:
|
||||
from ..pyethereum.transactions import Transaction
|
||||
from .. import rlp
|
||||
etx = rlp.decode(bytes.fromhex(self.serialized2), Transaction)
|
||||
d = etx.to_dict()
|
||||
o['router_gas'] = d['startgas']
|
||||
|
||||
class Sent(TxBase.Sent, OnlineSigned):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ class Signed(Completed, TxBase.Signed):
|
|||
self.disable_fee_check = True
|
||||
txid = CoinTxID(etx.hash.hex())
|
||||
assert txid == self.coin_txid, "txid in tx.serialized doesn't match value in MMGen transaction file"
|
||||
self.gas = o['startGas']
|
||||
self.txobj = o
|
||||
return d # 'token_addr', 'decimals' required by Token subclass
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ class Unsigned(Completed, TxBase.Unsigned):
|
|||
'nonce': ETHNonce(d['nonce']),
|
||||
'chainId': None if d['chainId'] == 'None' else Int(d['chainId']),
|
||||
'data': HexStr(d['data'])}
|
||||
self.gas = o['startGas']
|
||||
self.txobj = o
|
||||
return d # 'token_addr', 'decimals' required by Token subclass
|
||||
|
||||
|
|
@ -114,11 +113,12 @@ class TokenUnsigned(TokenCompleted, Unsigned):
|
|||
o['token_to'] = o['to']
|
||||
if self.is_swap:
|
||||
o['expiry'] = Int(d['expiry'])
|
||||
o['router_gas'] = Int(d['router_gas'])
|
||||
|
||||
async def do_sign(self, o, wif):
|
||||
t = Token(self.cfg, self.proto, o['token_addr'], decimals=o['decimals'])
|
||||
tdata = t.create_transfer_data(o['to'], o['amt'], op=self.token_op)
|
||||
tx_in = t.make_tx_in(gas=self.gas, gasPrice=o['gasPrice'], nonce=o['nonce'], data=tdata)
|
||||
tx_in = t.make_tx_in(gas=o['startGas'], gasPrice=o['gasPrice'], nonce=o['nonce'], data=tdata)
|
||||
res = await t.txsign(tx_in, wif, o['from'], chain_id=o['chainId'])
|
||||
self.serialized = res.txhex
|
||||
self.coin_txid = res.txid
|
||||
|
|
@ -131,7 +131,7 @@ class TokenUnsigned(TokenCompleted, Unsigned):
|
|||
self.swap_memo.encode(),
|
||||
o['expiry'])
|
||||
tx_in = c.make_tx_in(
|
||||
gas = self.gas * (7 if self.cfg.test_suite else 2),
|
||||
gas = o['router_gas'],
|
||||
gasPrice = o['gasPrice'],
|
||||
nonce = o['nonce'] + 1,
|
||||
data = cdata)
|
||||
|
|
|
|||
|
|
@ -447,7 +447,9 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
|
|||
return self._swaptxcreate_ui_common(t)
|
||||
|
||||
def swaptxcreate5b(self):
|
||||
t = self._swaptxcreate(['ETH.MM1', '98.7654321', 'ETH', f'{dfl_sid}:E:12'])
|
||||
t = self._swaptxcreate(
|
||||
['ETH.MM1', '98.7654321', 'ETH', f'{dfl_sid}:E:12'],
|
||||
add_opts = ['--gas=58000', '--router-gas=500000'])
|
||||
return self._swaptxcreate_ui_common(t)
|
||||
|
||||
def swaptxsign1(self):
|
||||
|
|
|
|||
3
test/overlay/fakemods/mmgen/proto/eth/tx/base.py
Executable file
3
test/overlay/fakemods/mmgen/proto/eth/tx/base.py
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
from .base_orig import *
|
||||
|
||||
TokenBase.dfl_router_gas = 525000
|
||||
Loading…
Add table
Add a link
Reference in a new issue