cmdtest.py ethdev: new CmdTestEthdevMethods class

This commit is contained in:
The MMGen Project 2025-03-29 09:30:15 +00:00
commit c08fbd2cc2
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 317 additions and 203 deletions

View file

@ -71,3 +71,8 @@ def ec_recover_pubkey(cfg, message, sig, msghash_type):
*ecdsa_raw_recover(
hash_message(cfg, message, msghash_type), tuple(int(hexstr, 16) for hexstr in (v, r, s)))
)
def compute_contract_addr(cfg, deployer_addr, nonce):
from . import rlp
encoded = rlp.encode([bytes.fromhex(deployer_addr), nonce])
return get_keccak(cfg)(encoded).hexdigest()[-40:]

View file

@ -14,11 +14,11 @@ test.cmdtest_d.automount_eth: Ethereum automount autosigning tests for the cmdte
import os, re
from .autosign import CmdTestAutosignThreaded
from .ethdev import CmdTestEthdev, parity_devkey_fn
from .ethdev import CmdTestEthdev, CmdTestEthdevMethods
from .include.common import dfl_words_file
from ..include.common import cfg
from ..include.common import cfg, joinpath
class CmdTestAutosignETH(CmdTestAutosignThreaded, CmdTestEthdev):
class CmdTestAutosignETH(CmdTestAutosignThreaded, CmdTestEthdev, CmdTestEthdevMethods):
'automounted transacting operations for Ethereum via ethdev'
networks = ('eth', 'etc')
@ -41,8 +41,8 @@ class CmdTestAutosignETH(CmdTestAutosignThreaded, CmdTestEthdev):
('token_deploy1c', 'deploying ERC20 token #1 (Token)'),
('tx_status2', 'getting the transaction status'),
('token_fund_user', 'transferring token funds from dev to user'),
('token_addrgen_addr1', 'generating token addresses'),
('token_addrimport_addr1', 'importing token addresses using token address (MM1)'),
('token_addrgen', 'generating token addresses'),
('token_addrimport', 'importing token addresses using token address (MM1)'),
('token_bal1', f'the {cfg.coin} balance and token balance'),
('create_token_tx', 'creating a token transaction'),
('send_token_tx', 'sending a token transaction'),
@ -62,33 +62,11 @@ class CmdTestAutosignETH(CmdTestAutosignThreaded, CmdTestEthdev):
self.txop_opts = ['--autosign', '--regtest=1', '--quiet']
def fund_mmgen_address(self):
keyfile = os.path.join(self.tmpdir, parity_devkey_fn)
t = self.spawn(
'mmgen-txdo',
self.eth_args
+ [f'--keys-from-file={keyfile}']
+ ['--fee=40G', '98831F3A:E:1,123.456', dfl_words_file],
)
t.expect('efresh balance:\b', 'q')
t.expect('from: ', '10')
t.expect('(Y/n): ', 'y')
t.expect('(Y/n): ', 'y')
t.expect('(y/N): ', 'n')
t.expect('view: ', 'n')
t.expect('confirm: ', 'YES')
return t
return self._fund_mmgen_address(arg='98831F3A:E:1,123.456')
def create_tx(self):
self.insert_device_online()
t = self.spawn('mmgen-txcreate', self.txop_opts + ['-B', '98831F3A:E:11,54.321'])
t = self.txcreate_ui_common(
t,
caller = 'txcreate',
input_sels_prompt = 'to spend from',
inputs = '1',
file_desc = 'transaction',
interactive_fee = '50G',
fee_desc = 'transaction fee or gas price')
t = self._create_tx(fee='50G', args=['98831F3A:E:11,54.321'], add_opts=self.txop_opts)
t.read()
self.remove_device_online()
return t
@ -96,49 +74,38 @@ class CmdTestAutosignETH(CmdTestAutosignThreaded, CmdTestEthdev):
def run_autosign_setup(self):
return self.run_setup(mn_type='bip39', mn_file='test/ref/98831F3A.bip39', use_dfl_wallet=None)
def send_tx(self, add_args=[]):
def send_tx(self):
self._wait_signed('transaction')
self.insert_device_online()
t = self.spawn('mmgen-txsend', self.txop_opts + add_args, no_passthru_opts=['coin'])
t.view_tx('t')
t.expect('(y/N): ', 'n')
self._do_confirm_send(t, quiet=True)
t.written_to_file('Sent automount transaction')
t = self._send_tx(desc='automount transaction', add_opts=self.txop_opts)
t.read()
self.remove_device_online()
return t
def token_fund_user(self):
return self.token_transfer_ops(op='do_transfer', num_tokens=1)
def token_addrgen(self):
return self._token_addrgen(mm_idxs=[11], naddrs=3)
def token_addrgen_addr1(self):
return self.token_addrgen(num_tokens=1)
def token_addrimport(self):
return self._token_addrimport('token_addr1', '11-13', expect='3/3')
def token_fund_user(self):
return self._token_transfer_ops(op='fund_user', mm_idxs=[11])
def token_bal1(self):
return self.token_bal(pat=r':E:11\s+1000\s+54\.321\s+')
return self._bal_check(pat=r':E:11\s+1000\s+54\.321\s+')
def token_bal2(self):
return self.token_bal(pat=r':E:11\s+998.76544\s+54.318\d+\s+.*:E:12\s+1\.23456\s+')
def token_bal(self, pat):
self.mining_delay()
t = self.spawn('mmgen-tool', ['--regtest=1', '--token=mm1', 'twview', 'wide=1'])
text = t.read(strip_color=True)
assert re.search(pat, text, re.DOTALL), f'output failed to match regex {pat}'
return t
return self._bal_check(pat=r':E:11\s+998.76544\s+54.318\d+\s+.*:E:12\s+1\.23456\s+')
def create_token_tx(self):
self.insert_device_online()
t = self.txcreate_ui_common(
self.spawn(
'mmgen-txcreate',
self.txop_opts + ['--token=MM1', '-B', '--fee=50G', '98831F3A:E:12,1.23456']),
inputs = '1',
input_sels_prompt = 'to spend from',
file_desc = 'Unsigned automount transaction')
t = self._create_token_tx(
cmd = 'txcreate',
fee = '50G',
args = ['98831F3A:E:12,1.23456'],
add_opts = self.txop_opts)
t.read()
self.remove_device_online()
return t
def send_token_tx(self):
return self.send_tx()
send_token_tx = send_tx

View file

@ -26,8 +26,9 @@ from collections import namedtuple
from subprocess import run, PIPE, DEVNULL
from pathlib import Path
from mmgen.color import yellow, blue, cyan, set_vt100
from mmgen.color import red, yellow, blue, cyan, set_vt100
from mmgen.util import msg, rmsg, die
from mmgen.proto.eth.misc import compute_contract_addr
from ..include.common import (
cfg,
@ -43,8 +44,8 @@ from ..include.common import (
silence,
end_silence,
gr_uc,
stop_test_daemons
)
stop_test_daemons)
from .include.common import (
ref_dir,
dfl_words_file,
@ -54,8 +55,9 @@ from .include.common import (
tw_comment_lat_cyr_gr,
get_file_with_ext,
ok_msg,
Ctrl_U
)
Ctrl_U,
cleanup_env)
from .base import CmdTestBase
from .shared import CmdTestShared
from .httpd.etherscan import EtherscanServer
@ -120,7 +122,227 @@ def set_vbals(daemon_id):
coin = cfg.coin
class CmdTestEthdev(CmdTestBase, CmdTestShared):
class CmdTestEthdevMethods: # mixin class
def _addrgen(self, addrs='1-3,11-13,21-23', no_msg=False):
t = self.spawn(
'mmgen-addrgen',
[f'--coin={self.proto.coin}'] + self.eth_args + [dfl_words_file, addrs],
no_msg = no_msg,
no_passthru_opts = True)
t.written_to_file('Addresses')
return t
def _create_tx(self, *, fee, args, add_opts=[]):
return self.txcreate_ui_common(
self.spawn('mmgen-txcreate', add_opts + ['-B'] + args),
caller = 'txcreate',
input_sels_prompt = 'to spend from',
inputs = '1',
file_desc = 'transaction',
interactive_fee = fee,
fee_desc = 'transaction fee or gas price')
def _send_tx(self, *, desc='transaction', add_opts=[]):
t = self.spawn('mmgen-txsend', add_opts, no_passthru_opts=['coin'])
t.view_tx('t')
t.expect('(y/N): ', 'n')
self._do_confirm_send(t, quiet=True)
t.written_to_file(f'Sent {desc}')
return t
def _txdo(self, *, args, acct, fee='50G'):
t = self.txcreate(
args,
acct = acct,
caller = 'txdo',
no_read = True,
bad_input_sels = False,
interactive_fee = fee,
print_listing = False)
t.written_to_file('Signed transaction')
t.expect('confirm: ', 'YES\n')
return t
def _txbump(self, *, fee, ext, add_opts=[], add_args=[]):
ext = ext.format('' if self.cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn('mmgen-txbump', self.eth_args + add_opts + ['--yes', txfile] + add_args)
t.expect('or gas price: ', fee+'\n')
return t
def _tx_receipt(self, ext='{}.regtest.sigtx'):
self.mining_delay()
return self.txsend(
ext = ext,
add_args = ['--receipt'],
return_early = True,
env = cleanup_env(cfg=self.cfg))
def _fund_mmgen_address(self, arg):
return self._txdo(
args = [f'--keys-from-file={joinpath(self.tmpdir, parity_devkey_fn)}', arg, dfl_words_file],
acct = '10')
def _token_addrgen(self, *, mm_idxs, naddrs):
self.spawn(msg_only=True)
for idx in mm_idxs:
t = self._addrgen(addrs=f'{idx}-{idx+naddrs-1}', no_msg=True)
return t
def _token_addrimport(self, addr_file, addr_range, expect, extra_args=[]):
token_addr = self.read_from_tmpfile(addr_file).strip()
return self.addrimport(
ext = f'[{addr_range}]{{}}.regtest.addrs',
expect = expect,
add_args = ['--token-addr='+token_addr]+extra_args)
def _get_contract_address(self, deployer_addr):
t = self.spawn(
'mmgen-cli',
['--regtest=1', 'eth_getTransactionCount', '0x'+deployer_addr, 'pending'],
env = cleanup_env(cfg=self.cfg),
silent = True,
no_msg = True)
nonce = t.read().strip()
imsg(f'Nonce: {red(nonce)}')
ret = compute_contract_addr(self.cfg, deployer_addr, int(nonce, 16))
imsg(f'Computed contract address: {blue(ret)}')
return ret
async def _token_deploy(self, num, key, gas, mmgen_cmd='txdo', gas_price='8G', get_receipt=True):
keyfile = joinpath(self.tmpdir, parity_devkey_fn)
fn = joinpath(self.tmpdir, 'mm'+str(num), key+'.bin')
args = [
'-B',
f'--fee={gas_price}',
f'--gas={gas}',
f'--contract-data={fn}',
f'--inputs={dfl_devaddr}',
'--yes',
]
contract_addr = self._get_contract_address(dfl_devaddr)
if key == 'Token':
self.write_to_tmpfile(f'token_addr{num}', contract_addr+'\n')
if mmgen_cmd == 'txdo':
args += ['-k', keyfile]
t = self.spawn('mmgen-'+mmgen_cmd, self.eth_args + args)
if mmgen_cmd == 'txcreate':
t.written_to_file('transaction')
ext = '[0,8000]{}.regtest.rawtx'.format('' if self.cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn(
'mmgen-txsign',
self.eth_args + ['--yes', '-k', keyfile, txfile], no_msg=True, no_passthru_opts=['coin'])
self.txsign_ui_common(t, ni=True)
txfile = txfile.replace('.rawtx', '.sigtx')
t = self.spawn('mmgen-txsend',
self.eth_args + [txfile], no_msg=True, no_passthru_opts=['coin'])
txid = self.txsend_ui_common(t,
caller = mmgen_cmd,
quiet = mmgen_cmd == 'txdo' or not self.cfg.debug,
bogus_send = False)
_ = strip_ansi_escapes(t.expect_getend('Contract address: '))
assert _ == contract_addr, f'Contract address mismatch: {_} != {contract_addr}'
if get_receipt:
if (await self.get_tx_receipt(txid)).status == 0:
die(2, f'Contract {num}:{key} failed to execute. Aborting')
if key == 'Token':
imsg(f'\nToken MM{num} deployed!')
return t
async def _token_deploy_math(self, *, num, get_receipt=True, mmgen_cmd='txdo'):
return await self._token_deploy(
num=num, key='SafeMath', gas=500_000, get_receipt=get_receipt, mmgen_cmd=mmgen_cmd)
async def _token_deploy_owned(self, *, num, get_receipt=True):
return await self._token_deploy(
num=num, key='Owned', gas=1_000_000, get_receipt=get_receipt)
async def _token_deploy_token(self, *, num, get_receipt=True):
return await self._token_deploy(
num=num, key='Token', gas=4_000_000, gas_price='7G', get_receipt=get_receipt)
def _bal_check(self, *, pat):
self.mining_delay()
t = self.spawn('mmgen-tool', ['--regtest=1', '--token=mm1', 'twview', 'wide=1'])
text = t.read(strip_color=True)
assert re.search(pat, text, re.DOTALL), f'output failed to match regex {pat}'
return t
def _create_token_tx(self, *, cmd, fee, args, add_opts=[]):
return self.txcreate_ui_common(
self.spawn(
f'mmgen-{cmd}',
['--token=MM1', '-B', f'--fee={fee}'] + add_opts + args),
inputs = '1',
input_sels_prompt = 'to spend from',
caller = cmd,
file_desc = 'Unsigned automount transaction')
async def _token_transfer_ops(self, *, op, mm_idxs, amt=1000, get_receipt=True, sid=dfl_sid):
self.spawn(msg_only=True)
from mmgen.tool.wallet import tool_cmd
usr_mmaddrs = [f'{sid}:E:{i}' for i in mm_idxs]
from mmgen.proto.eth.contract import ResolvedToken
async def fund_user(rpc):
for i in range(len(usr_mmaddrs)):
tk = await ResolvedToken(
self.cfg,
self.proto,
rpc,
self.read_from_tmpfile(f'token_addr{i+1}').strip())
imsg_r('\n' + await tk.info())
imsg('dev token balance (pre-send): {}'.format(await tk.get_balance(dfl_devaddr)))
imsg(f'Sending {amt} {self.proto.dcoin} to address {usr_addrs[i]} ({usr_mmaddrs[i]})')
txid = await tk.transfer(
from_addr = dfl_devaddr,
to_addr = usr_addrs[i],
amt = amt,
key = dfl_devkey,
gas = self.proto.coin_amt(120000, from_unit='wei'),
gasPrice = self.proto.coin_amt(8, from_unit='Gwei'))
if get_receipt and (await self.get_tx_receipt(txid)).status == 0:
die(2, 'Transfer of token funds failed. Aborting')
async def show_bals(rpc):
for i in range(len(usr_mmaddrs)):
tk = await ResolvedToken(
self.cfg,
self.proto,
rpc,
self.read_from_tmpfile(f'token_addr{i+1}').strip())
imsg('Token: {}'.format(await tk.get_symbol()))
imsg(f'dev token balance: {await tk.get_balance(dfl_devaddr)}')
imsg('usr token balance: {} ({} {})'.format(
await tk.get_balance(usr_addrs[i]),
usr_mmaddrs[i],
usr_addrs[i]))
def gen_addr(addr):
return tool_cmd(
self.cfg, cmdname='gen_addr', proto=self.proto).gen_addr(addr, wallet=dfl_words_file)
silence()
usr_addrs = list(map(gen_addr, usr_mmaddrs))
if op == 'show_bals':
await show_bals(await self.rpc)
elif op == 'fund_user':
await fund_user(await self.rpc)
end_silence()
return 'ok'
class CmdTestEthdev(CmdTestBase, CmdTestShared, CmdTestEthdevMethods):
'Ethereum transacting, token deployment and tracking wallet operations'
networks = ('eth', 'etc')
passthru_opts = ('coin', 'daemon_id', 'eth_daemon_id', 'http_timeout', 'rpc_backend')
@ -595,7 +817,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
make_key()
signer_addr = self.keystore_data['address']
self.write_to_tmpfile( 'signer_addr', signer_addr + '\n')
self.write_to_tmpfile('signer_addr', signer_addr + '\n')
imsg(f' Keystore: {self.keystore_dir}')
imsg(f' Signer key: {self.keystore_data["key"]}')
@ -647,13 +869,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
async def wallet_upgrade2(self):
return await self._wallet_upgrade('tracking-wallet-v2.json', 'token params field', 'network field')
def addrgen(self, addrs='1-3,11-13,21-23'):
t = self.spawn(
'mmgen-addrgen',
[f'--coin={self.proto.coin}'] + self.eth_args + [dfl_words_file, addrs],
no_passthru_opts = True)
t.written_to_file('Addresses')
return t
def addrgen(self):
return self._addrgen()
def addrimport(
self,
@ -716,7 +933,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
t.read()
return t
def txsign(self, ni=False, ext='{}.regtest.rawtx', add_args=[], dev_send=False):
def txsign(self, ni=False, ext='{}.regtest.rawtx', add_args=[], dev_send=False, has_label=True):
ext = ext.format('' if self.cfg.debug_utf8 else '')
keyfile = joinpath(self.tmpdir, parity_devkey_fn)
txfile = self.get_file_with_ext(ext, no_dot=True)
@ -729,18 +946,31 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
+ add_args
+ [txfile, dfl_words_file],
no_passthru_opts = ['coin'])
return self.txsign_ui_common(t, ni=ni, has_label=True)
return self.txsign_ui_common(t, ni=ni, has_label=has_label)
def txsend(self, ext='{}.regtest.sigtx', add_args=[], test=False):
def txsend(
self,
ext = '{}.regtest.sigtx',
add_args = [],
test = False,
return_early = False,
has_label = True,
env = {}):
ext = ext.format('' if self.cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn('mmgen-txsend', self.eth_args + add_args + [txfile], no_passthru_opts=['coin'])
t = self.spawn(
'mmgen-txsend',
self.eth_args + add_args + [txfile],
no_passthru_opts = ['coin'],
env = env)
if return_early:
return t
self.txsend_ui_common(
t,
quiet = not self.cfg.debug,
bogus_send = False,
test = test,
has_label = True)
has_label = has_label)
return t
def txview(self, ext_fs):
@ -931,12 +1161,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
interactive_fee = '40G',
fee_info_data = ('0.00084', '40'))
def txbump(self, ext=',40000]{}.regtest.rawtx', fee='50G', add_args=[]):
ext = ext.format('' if self.cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn('mmgen-txbump', self.eth_args + add_args + ['--yes', txfile])
t.expect('or gas price: ', fee+'\n')
return t
def txbump(self):
return self._txbump(fee='50G', ext=',40000]{}.regtest.rawtx')
def txsign4(self):
return self.txsign(ext='.45495,50000]{}.regtest.rawtx', add_args=['--no-quiet', '--no-yes'])
@ -1053,6 +1279,8 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
tx = await NewTX(cfg=self.cfg, proto=self.proto, target='tx')
tx.rpc = await self.rpc
res = await tx.get_receipt(txid)
if not res:
die(1, f'Error getting receipt for transaction {txid}')
imsg(f'Gas sent: {res.gas_sent.hl():<9} {(res.gas_sent*res.gas_price).hl2(encl="()")}')
imsg(f'Gas used: {res.gas_used.hl():<9} {(res.gas_used*res.gas_price).hl2(encl="()")}')
imsg(f'Gas price: {res.gas_price.hl()}')
@ -1060,50 +1288,23 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
omsg(yellow('Warning: all gas was used!'))
return res
async def token_deploy(self, num, key, gas, mmgen_cmd='txdo', gas_price='8G'):
keyfile = joinpath(self.tmpdir, parity_devkey_fn)
fn = joinpath(self.tmpdir, 'mm'+str(num), key+'.bin')
args = [
'-B',
f'--fee={gas_price}',
f'--gas={gas}',
f'--contract-data={fn}',
f'--inputs={dfl_devaddr}',
'--yes',
]
if mmgen_cmd == 'txdo':
args += ['-k', keyfile]
t = self.spawn('mmgen-'+mmgen_cmd, self.eth_args + args)
if mmgen_cmd == 'txcreate':
t.written_to_file('transaction')
ext = '[0,8000]{}.regtest.rawtx'.format('' if self.cfg.debug_utf8 else '')
txfile = self.get_file_with_ext(ext, no_dot=True)
t = self.spawn(
'mmgen-txsign',
self.eth_args + ['--yes', '-k', keyfile, txfile], no_msg=True, no_passthru_opts=['coin'])
self.txsign_ui_common(t, ni=True)
txfile = txfile.replace('.rawtx', '.sigtx')
t = self.spawn('mmgen-txsend',
self.eth_args + [txfile], no_msg=True, no_passthru_opts=['coin'])
txid = self.txsend_ui_common(t,
caller = mmgen_cmd,
quiet = mmgen_cmd == 'txdo' or not self.cfg.debug,
bogus_send = False)
addr = strip_ansi_escapes(t.expect_getend('Contract address: '))
if (await self.get_tx_receipt(txid)).status == 0:
die(2, f'Contract {num}:{key} failed to execute. Aborting')
if key == 'Token':
self.write_to_tmpfile(f'token_addr{num}', addr+'\n')
imsg(f'\nToken MM{num} deployed!')
return t
async def token_deploy1a(self):
return await self.token_deploy(num=1, key='SafeMath', gas=500_000)
return await self._token_deploy_math(num=1)
async def token_deploy1b(self):
return await self.token_deploy(num=1, key='Owned', gas=1_000_000)
return await self._token_deploy_owned(num=1)
async def token_deploy1c(self):
return await self.token_deploy(num=1, key='Token', gas=4_000_000, gas_price='7G')
return await self._token_deploy_token(num=1)
async def token_deploy2a(self): # test create, sign, send:
return await self._token_deploy_math(num=2, mmgen_cmd='txcreate')
async def token_deploy2b(self):
return await self._token_deploy_owned(num=2)
async def token_deploy2c(self):
return await self._token_deploy_token(num=2)
def tx_status2(self):
return self.tx_status(
@ -1113,79 +1314,14 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
def bal6(self):
return self.bal5()
async def token_deploy2a(self): # test create, sign, send:
return await self.token_deploy(num=2, key='SafeMath', gas=500_000, mmgen_cmd='txcreate')
async def token_deploy2b(self):
return await self.token_deploy(num=2, key='Owned', gas=1_000_000)
async def token_deploy2c(self):
return await self.token_deploy(num=2, key='Token', gas=4_000_000)
async def token_transfer_ops(self, op, amt=1000, num_tokens=2):
self.spawn(msg_only=True)
sid = dfl_sid
from mmgen.tool.wallet import tool_cmd
usr_mmaddrs = [f'{sid}:E:{i}' for i in (11, 21)][:num_tokens]
from mmgen.proto.eth.contract import ResolvedToken
async def do_transfer(rpc):
for i in range(num_tokens):
tk = await ResolvedToken(
self.cfg,
self.proto,
rpc,
self.read_from_tmpfile(f'token_addr{i+1}').strip())
imsg_r('\n' + await tk.info())
imsg('dev token balance (pre-send): {}'.format(await tk.get_balance(dfl_devaddr)))
imsg(f'Sending {amt} {self.proto.dcoin} to address {usr_addrs[i]} ({usr_mmaddrs[i]})')
txid = await tk.transfer(
from_addr = dfl_devaddr,
to_addr = usr_addrs[i],
amt = amt,
key = dfl_devkey,
gas = self.proto.coin_amt(120000, from_unit='wei'),
gasPrice = self.proto.coin_amt(8, from_unit='Gwei'))
if (await self.get_tx_receipt(txid)).status == 0:
die(2, 'Transfer of token funds failed. Aborting')
async def show_bals(rpc):
for i in range(num_tokens):
tk = await ResolvedToken(
self.cfg,
self.proto,
rpc,
self.read_from_tmpfile(f'token_addr{i+1}').strip())
imsg('Token: {}'.format(await tk.get_symbol()))
imsg(f'dev token balance: {await tk.get_balance(dfl_devaddr)}')
imsg('usr token balance: {} ({} {})'.format(
await tk.get_balance(usr_addrs[i]),
usr_mmaddrs[i],
usr_addrs[i]))
def gen_addr(addr):
return tool_cmd(
self.cfg, cmdname='gen_addr', proto=self.proto).gen_addr(addr, wallet=dfl_words_file)
silence()
usr_addrs = list(map(gen_addr, usr_mmaddrs))
if op == 'show_bals':
await show_bals(await self.rpc)
elif op == 'do_transfer':
await do_transfer(await self.rpc)
end_silence()
return 'ok'
def token_fund_users(self):
return self.token_transfer_ops(op='do_transfer')
return self._token_transfer_ops(op='fund_user', mm_idxs=[11, 21])
def token_user_bals(self):
return self.token_transfer_ops(op='show_bals')
return self._token_transfer_ops(op='show_bals', mm_idxs=[11, 21])
def token_addrgen(self, num_tokens=2):
t = self.addrgen(addrs='11-13')
if num_tokens == 1:
return t
ok_msg()
return self.addrgen(addrs='21-23')
def token_addrgen(self):
return self._token_addrgen(mm_idxs=[11, 21], naddrs=3)
def token_addrimport_badaddr1(self):
t = self.addrimport(
@ -1205,21 +1341,14 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
t.expect('could not be resolved')
return t
def token_addrimport(self, addr_file, addr_range, expect, extra_args=[]):
token_addr = self.read_from_tmpfile(addr_file).strip()
return self.addrimport(
ext = f'[{addr_range}]{{}}.regtest.addrs',
expect = expect,
add_args = ['--token-addr='+token_addr]+extra_args)
def token_addrimport_addr1(self):
return self.token_addrimport('token_addr1', '11-13', expect='3/3')
return self._token_addrimport('token_addr1', '11-13', expect='3/3')
def token_addrimport_addr2(self):
return self.token_addrimport('token_addr2', '21-23', expect='3/3')
return self._token_addrimport('token_addr2', '21-23', expect='3/3')
def token_addrimport_batch(self):
return self.token_addrimport('token_addr1', '11-13', expect='3 addresses', extra_args=['--batch'])
return self._token_addrimport('token_addr1', '11-13', expect='3 addresses', extra_args=['--batch'])
def token_addrimport_sym(self):
return self.addrimport(
@ -1285,7 +1414,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
def token_txcreate2(self):
return self.token_txcreate(args=[burn_addr+', '+amt2], token='mm1')
def token_txbump(self):
return self.txbump(ext=amt2+',50000]{}.regtest.rawtx', fee='56G', add_args=['--token=mm1'])
return self._txbump(ext=amt2+',50000]{}.regtest.rawtx', fee='56G', add_opts=['--token=MM1'])
def token_txsign2(self):
return self.token_txsign(ext=amt2+',50000]{}.regtest.rawtx', token='mm1')
def token_txsend2(self):

View file

@ -118,6 +118,7 @@ class CmdTestShared:
return t
t.view_tx(view)
if not txdo:
t.expect('(y/N): ', ('n', 'y')[save])
t.written_to_file(file_desc)
@ -192,6 +193,18 @@ class CmdTestShared:
return txid
def txbump_ui_common(self, t, *, fee, fee_desc='transaction fee', bad_fee=None):
t.expect('(Y/n): ', 'n') # network-estimated fee OK?
if bad_fee:
t.expect(f'{fee_desc}: ', f'{bad_fee}\n')
t.expect(f'{fee_desc}: ', f'{fee}\n')
t.expect('(Y/n): ', 'y') # fee OK?
t.expect('(Y/n): ', 'y') # signoff
t.expect('(y/N): ', 'n') # edit comment
t.expect('(y/N): ', 'y') # save TX?
t.written_to_file('Fee-bumped transaction')
return t
def txsign_end(self, t, tnum=None, has_label=False):
t.expect('Signing transaction')
t.do_comment(False, has_label=has_label)