From d8439ba691461201c43fcb244ad95b1c471b9154 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 6 Feb 2026 10:14:25 +0000 Subject: [PATCH] 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 --- mmgen/data/version | 2 +- mmgen/main_addrimport.py | 43 ++++++++++++++++++++++++++++++++++ test/cmdtest_d/xmr_autosign.py | 21 ++++++++++++++--- test/cmdtest_d/xmrwallet.py | 17 +++++++++----- 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index 0e6f7859..240a64f0 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -16.1.dev30 +16.1.dev31 diff --git a/mmgen/main_addrimport.py b/mmgen/main_addrimport.py index d8cc170d..8ced76a0 100755 --- a/mmgen/main_addrimport.py +++ b/mmgen/main_addrimport.py @@ -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, diff --git a/test/cmdtest_d/xmr_autosign.py b/test/cmdtest_d/xmr_autosign.py index fcb12da5..b84ae5cf 100755 --- a/test/cmdtest_d/xmr_autosign.py +++ b/test/cmdtest_d/xmr_autosign.py @@ -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) diff --git a/test/cmdtest_d/xmrwallet.py b/test/cmdtest_d/xmrwallet.py index ea46782d..64a93e72 100755 --- a/test/cmdtest_d/xmrwallet.py +++ b/test/cmdtest_d/xmrwallet.py @@ -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):