XMR compat: addrimport support

Example (assumes --autosign):

    $ mmgen-addrimport --coin=xmr

Testing/demo:

    $ test/cmdtest.py --coin=xmr -e -X addrimport_alice2 xmr_compat

More info:

    $ mmgen-addrimport --help
This commit is contained in:
The MMGen Project 2026-02-06 10:14:25 +00:00
commit d8439ba691
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 73 additions and 10 deletions

View file

@ -1 +1 @@
16.1.dev30
16.1.dev31

View file

@ -33,6 +33,10 @@ opts_data = {
'options': """
-h, --help Print this help message
--, --longhelp Print help message for long (global) options
-a, --autosign Import addresses from pre-created key-address file on the
removable device. The removable device is mounted and
unmounted automatically. This option is available for XMR
only (see XMR NOTES below).
-A, --address=ADDR Import the single coin address ADDR
-b, --batch Import all addresses in one RPC call
-l, --addrlist Address source is a flat list of non-MMGen coin addresses
@ -45,6 +49,25 @@ opts_data = {
-t, --token-addr=ADDR Import addresses for ERC20 token with address ADDR
""",
'notes': """
XMR NOTES
For Monero, --autosign is required, and a key-address file on the removable
device is used instead of an address file. Specifying the file explicitly
on the command line is not supported.
When mmgen-autosign setup (or xmr_setup) is run with the --xmrwallets
option, an ephemeral Monero wallet is created for each wallet number listed,
to be used for transaction signing. In addition, a key-address file is created
on the removable device, with an address and viewkey matching the base address
of each signing wallet.
This script uses that file to create an online view-only tracking wallet to
match each offline signing wallet. If a tracking wallet for a given address
already exists, it is left untouched and no action is performed. To create
additional tracking wallets, just specify new wallet numbers via --xmrwallets
during the offline setup process.
NOTES FOR BTC, LTC AND BCH
Rescanning now uses the scantxoutset RPC call and a selective scan of
@ -133,8 +156,28 @@ def check_opts(twctl):
return batch, rescan
def check_xmr_args():
for k in ('address', 'batch', 'addrlist', 'keyaddr_file', 'rescan', 'token_addr'):
if getattr(cfg, k):
die(1, 'Option --{} not supported for XMR'.format(k.replace('_', '-')))
if not cfg.autosign:
die(1, 'For XMR address import, --autosign is required')
if cfg._args:
die(1, 'Address file arg not supported with --autosign')
async def main():
if cfg._proto.base_coin == 'XMR':
from .tx.util import mount_removable_device
from .xmrwallet import op as xmrwallet_op
check_xmr_args()
mount_removable_device(cfg)
op = xmrwallet_op('create', cfg, None, None, compat_call=True)
if op.to_process:
await op.restart_wallet_daemon()
await op.main()
return
from .tw.ctl import TwCtl
twctl = await TwCtl(
cfg = cfg,

View file

@ -520,7 +520,8 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
cmd_group = (
('autosign_setup', 'autosign setup with Alice’s seed'),
('autosign_xmr_setup', 'autosign setup (creation of Monero signing wallets)'),
('create_watchonly_wallets', 'creating Alice’s watch-only wallets'),
('addrimport_alice', 'creating (importing) Alice’s watch-only wallets from key-address file'),
('addrimport_alice2', 'reimporting Alice’s watch-only wallets from key-address file'),
('gen_kafile_miner', 'generating key-address file for Miner'),
('create_wallet_miner', 'creating Monero wallet for Miner'),
('mine_initial_coins', 'mining initial coins'),
@ -601,8 +602,22 @@ class CmdTestXMRCompat(CmdTestXMRAutosign):
'--monero-wallet-rpc-password=passwOrd']
self.alice_opts = ['--alice', '--coin=xmr'] + self.alice_daemon_opts
def create_watchonly_wallets(self):
return self._create_wallets()
def addrimport_alice(self):
return self._addrimport_alice(create_address_files=True)
def addrimport_alice2(self):
return self._addrimport_alice(expect_str='Skipping.*Skipping')
def _addrimport_alice(self, *, expect_str=None, create_address_files=False):
self.insert_device_online()
t = self.spawn('mmgen-addrimport', self.alice_opts + self.autosign_opts)
if expect_str:
t.expect(expect_str, regex=True)
if create_address_files:
self._create_address_files(t, 'alice')
t.read() # required!
self.remove_device_online()
return t
async def mine_blocks_1(self):
return await self._mine_blocks(1)

View file

@ -293,6 +293,16 @@ class CmdTestXMRWallet(CmdTestBase):
def create_wallets_alice(self):
return self.create_wallets('alice')
def _create_address_files(self, t, user, wallet=None):
data = self.users[user]
for i in MMGenRange(wallet or data.kal_range).items:
write_data_to_file(
self.cfg,
data.addrfile_fs.format(i),
t.expect_getend('Address: '),
ask_overwrite = False,
quiet = True)
def create_wallets(self, user, wallet=None, add_opts=[], op='create'):
assert wallet is None or is_int(wallet), 'wallet arg'
data = self.users[user]
@ -311,12 +321,7 @@ class CmdTestXMRWallet(CmdTestBase):
+ [op]
+ ([] if data.autosign else [data.kafile])
+ [wallet or data.kal_range])
for i in MMGenRange(wallet or data.kal_range).items:
write_data_to_file(
self.cfg,
self.users[user].addrfile_fs.format(i),
t.expect_getend('Address: '),
quiet = True)
self._create_address_files(t, user, wallet)
return t
def new_addr_alice(self, spec, cfg, expect, kafile=None, do_autosign=False):