proto.eth.tx: minor cleanups, fixes

This commit is contained in:
The MMGen Project 2025-03-16 10:46:32 +00:00
commit ef640d10a9
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 37 additions and 32 deletions

View file

@ -21,6 +21,8 @@ proto.eth.contract: Ethereum ERC20 token classes
"""
from decimal import Decimal
from collections import namedtuple
from . import rlp
from . import erigon_sleep
@ -135,21 +137,21 @@ class TokenCommon(MMGenObject):
res = await self.rpc.call('eth_chainId')
chain_id = None if res is None else int(res, 16)
tx = Transaction(**tx_in).sign(key, chain_id)
etx = Transaction(**tx_in).sign(key, chain_id)
if tx.sender.hex() != from_addr:
die(3, f'Sender address {from_addr!r} does not match address of key {tx.sender.hex()!r}!')
if etx.sender.hex() != from_addr:
die(3, f'Sender address {from_addr!r} does not match address of key {etx.sender.hex()!r}!')
if self.cfg.debug:
msg('TOKEN DATA:')
pp_msg(tx.to_dict())
pp_msg(etx.to_dict())
msg('PARSED ABI DATA:\n {}'.format(
'\n '.join(parse_abi(tx.data.hex()))))
'\n '.join(parse_abi(etx.data.hex()))))
return (
rlp.encode(tx).hex(),
CoinTxID(tx.hash.hex())
)
return namedtuple('signed_contract_transaction', ['etx', 'txhex', 'txid'])(
etx,
rlp.encode(etx).hex(),
CoinTxID(etx.hash.hex()))
# The following are used for token deployment only:
@ -173,8 +175,8 @@ class TokenCommon(MMGenObject):
gasPrice,
nonce = int(await self.rpc.call('eth_getTransactionCount', '0x'+from_addr, 'pending'), 16),
method_sig = method_sig)
txhex, _ = await self.txsign(tx_in, key, from_addr)
return await self.txsend(txhex)
res = await self.txsign(tx_in, key, from_addr)
return await self.txsend(res.txhex)
class Token(TokenCommon):

View file

@ -30,11 +30,8 @@ class TxInfo(TxInfo):
def format_body(self, blockcount, nonmm_str, max_mmwid, enl, *, terse, sort):
tx = self.tx
m = {}
for k in ('inputs', 'outputs'):
if len(getattr(tx, k)):
m[k] = getattr(tx, k)[0].mmid if len(getattr(tx, k)) else ''
m[k] = ' ' + m[k].hl() if m[k] else ' ' + MMGenID.hlc(nonmm_str)
def mmid_disp(io):
return ' ' + (io.mmid.hl() if io.mmid else MMGenID.hlc(nonmm_str))
fs = """
From: {f}{f_mmid}
To: {t}{t_mmid}
@ -56,8 +53,8 @@ class TxInfo(TxInfo):
c = tx.proto.dcoin if len(tx.outputs) else '',
g = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
G = yellow(tx.pretty_fmt_fee(t['startGas'].to_unit('Kwei'))),
t_mmid = m['outputs'] if len(tx.outputs) else '',
f_mmid = m['inputs']) + '\n\n'
f_mmid = mmid_disp(tx.inputs[0]),
t_mmid = mmid_disp(tx.outputs[0]) if tx.outputs else '') + '\n\n'
def format_abs_fee(self, iwidth, /, *, color=None):
return self.tx.fee.fmt(iwidth, color=color) + (' (max)' if self.tx.txobj['data'] else '')

View file

@ -40,8 +40,7 @@ class Unsigned(Completed, TxBase.Unsigned):
self.txobj = o
return d # 'token_addr', 'decimals' required by Token subclass
async def do_sign(self, wif):
o = self.txobj
async def do_sign(self, o, wif):
o_conv = {
'to': bytes.fromhex(o['to'] or ''),
'startgas': o['startGas'].toWei(),
@ -59,10 +58,10 @@ class Unsigned(Completed, TxBase.Unsigned):
self.serialized = rlp.encode(etx).hex()
self.coin_txid = CoinTxID(etx.hash.hex())
if o['data']:
if o['data']: # contract-creating transaction
if o['to']:
assert self.txobj['token_addr'] == TokenAddr(self.proto, etx.creates.hex()), 'Token address mismatch'
else: # token- or contract-creating transaction
raise ValueError('contract-creating transaction cannot have to-address')
else:
self.txobj['token_addr'] = TokenAddr(self.proto, etx.creates.hex())
async def sign(self, tx_num_str, keys): # return TX object or False; don't exit or raise exception
@ -73,10 +72,12 @@ class Unsigned(Completed, TxBase.Unsigned):
except TransactionChainMismatch:
return False
o = self.txobj
msg_r(f'Signing transaction{tx_num_str}...')
try:
await self.do_sign(keys[0].sec.wif)
await self.do_sign(o, keys[0].sec.wif)
msg('OK')
from ....tx import SignedTX
return await SignedTX(cfg=self.cfg, data=self.__dict__, automount=self.automount)
@ -96,8 +97,7 @@ class TokenUnsigned(TokenCompleted, Unsigned):
o['data'] = t.create_data(o['to'], o['amt'])
o['token_to'] = t.transferdata2sendaddr(o['data'])
async def do_sign(self, wif):
o = self.txobj
async def do_sign(self, o, wif):
t = Token(self.cfg, self.proto, o['token_addr'], o['decimals'])
tx_in = t.make_tx_in(
to_addr = o['to'],
@ -105,7 +105,9 @@ class TokenUnsigned(TokenCompleted, Unsigned):
start_gas = self.start_gas,
gasPrice = o['gasPrice'],
nonce = o['nonce'])
(self.serialized, self.coin_txid) = await t.txsign(tx_in, wif, o['from'], chain_id=o['chainId'])
res = await t.txsign(tx_in, wif, o['from'], chain_id=o['chainId'])
self.serialized = res.txhex
self.coin_txid = res.txid
class AutomountUnsigned(TxBase.AutomountUnsigned, Unsigned):
pass

View file

@ -721,9 +721,9 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
self.eth_args
+ [f'--coin={self.proto.coin}']
+ ['--rpc-host=bad_host'] # ETH signing must work without RPC
+ add_args
+ ([], ['--yes'])[ni]
+ ([f'--keys-from-file={keyfile}'] if dev_send else [])
+ add_args
+ [txfile, dfl_words_file])
return self.txsign_ui_common(t, ni=ni, has_label=True)
@ -924,7 +924,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
return t
def txsign4(self):
return self.txsign(ni=True, ext='.45495,50000]{}.regtest.rawtx', dev_send=True)
return self.txsign(ext='.45495,50000]{}.regtest.rawtx', add_args=['--no-quiet', '--no-yes'])
def txsend4(self):
return self.txsend(ext='.45495,50000]{}.regtest.sigtx')
def bal4(self):
@ -1222,8 +1222,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
input_sels_prompt = 'to spend from',
add_comment = tx_comment_lat_cyr_gr,
file_desc = file_desc)
def token_txsign(self, ext='', token=''):
return self.txsign(ni=True, ext=ext, add_args=['--token='+token])
def token_txsign(self, ext='', token='', add_args=[], ni=True):
return self.txsign(ni=ni, ext=ext, add_args=[f'--token={token}'] + add_args)
def token_txsend(self, ext='', token=''):
return self.txsend(ext=ext, add_args=['--token='+token])
@ -1232,7 +1232,11 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
def token_txview1_raw(self):
return self.txview(ext_fs='1.23456,50000]{}.regtest.rawtx')
def token_txsign1(self):
return self.token_txsign(ext='1.23456,50000]{}.regtest.rawtx', token='mm1')
return self.token_txsign(
ext = '1.23456,50000]{}.regtest.rawtx',
token = 'mm1',
ni = False,
add_args = ['--no-quiet', '--no-yes'])
def token_txsend1(self):
return self.token_txsend(ext='1.23456,50000]{}.regtest.sigtx', token='mm1')
def token_txview1_sig(self):