From cbd441906a4b27e8509748a5c367f539236bb11c Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 23 Oct 2026 17:01:32 +0000 Subject: [PATCH] various changes, fixes and cleanups --- mmgen/obj.py | 3 +++ mmgen/proto/xmr/tx/online.py | 2 ++ mmgen/proto/xmr/tx/unsigned.py | 3 ++- mmgen/tx/base.py | 6 +++--- mmgen/tx/file.py | 17 ++++++++++------- mmgen/tx/info.py | 21 +++++++++++++-------- mmgen/tx/new_swap.py | 3 ++- mmgen/xmrwallet/file/__init__.py | 5 ++--- mmgen/xmrwallet/file/tx.py | 2 -- test/cmdtest_d/misc.py | 14 +++++++++++--- test/cmdtest_d/xmrswap.py | 2 +- 11 files changed, 49 insertions(+), 29 deletions(-) diff --git a/mmgen/obj.py b/mmgen/obj.py index 45c808fa..ca2668ca 100644 --- a/mmgen/obj.py +++ b/mmgen/obj.py @@ -283,6 +283,9 @@ class Int(int, Hilite, InitErrors): class NonNegativeInt(Int): min_val = 0 +class PositiveInt(Int): + min_val = 1 + class MMGenIdx(Int): min_val = 1 diff --git a/mmgen/proto/xmr/tx/online.py b/mmgen/proto/xmr/tx/online.py index a03ae186..b7a4d761 100644 --- a/mmgen/proto/xmr/tx/online.py +++ b/mmgen/proto/xmr/tx/online.py @@ -14,6 +14,7 @@ from .completed import Completed class OnlineSigned(Completed): desc = 'signed transaction' + ext = 'asigtx' async def compat_send(self): """ @@ -55,3 +56,4 @@ class AutomountOnlineSigned(OnlineSigned): class AutomountSent(AutomountOnlineSigned): desc = 'sent automount transaction' + ext = 'asubtx' diff --git a/mmgen/proto/xmr/tx/unsigned.py b/mmgen/proto/xmr/tx/unsigned.py index 645c840f..469f2ffc 100644 --- a/mmgen/proto/xmr/tx/unsigned.py +++ b/mmgen/proto/xmr/tx/unsigned.py @@ -16,4 +16,5 @@ class Unsigned(Completed): pass class AutomountUnsigned(Unsigned): - pass + desc = 'unsigned automount transaction' + ext = 'arawtx' diff --git a/mmgen/tx/base.py b/mmgen/tx/base.py index bb87d432..adc5f418 100644 --- a/mmgen/tx/base.py +++ b/mmgen/tx/base.py @@ -20,8 +20,8 @@ from ..obj import ( TwComment, CoinTxID, HexStr, - NonNegativeInt -) + NonNegativeInt, + PositiveInt) from ..amt import CoinAmtChk from ..addr import MMGenID, CoinAddr from ..util import msg, ymsg, fmt, remove_dups, make_timestamp, die @@ -95,7 +95,7 @@ class Base(MMGenObject): 'token_vault_addr': None, # nosec # B105 'serialized2': None, 'is_memoless': None, - 'refnum': None, + 'refnum': PositiveInt, 'coin_txid2': CoinTxID} file_format = 'json' non_mmgen_inputs_msg = f""" diff --git a/mmgen/tx/file.py b/mmgen/tx/file.py index c44eeb99..480138ad 100644 --- a/mmgen/tx/file.py +++ b/mmgen/tx/file.py @@ -23,10 +23,6 @@ import os, json from ..util import ymsg, make_chksum_6, die from ..obj import MMGenObject, HexStr, MMGenTxID, CoinTxID, MMGenTxComment -def get_monero_proto(tx, data): - from ..protocol import init_proto - return init_proto(tx.cfg, 'XMR', network=data['MoneroMMGenTX']['data']['network']) - class txfile_json_encoder(json.JSONEncoder): def default(self, o): if type(o).__name__.endswith('Amt'): @@ -60,6 +56,7 @@ def eval_io_data(tx, data, *, desc): class MMGenTxFile(MMGenObject): data_label = 'MMGenTransaction' + xmr_data_label = 'MoneroMMGenTX' attrs = { 'chain': None, 'txid': MMGenTxID, @@ -93,10 +90,16 @@ class MMGenTxFile(MMGenObject): def parse_data_json(self, data, get_proto_only): tx = self.tx tx.file_format = 'json' - outer_data = json.loads(data) - if 'MoneroMMGenTX' in outer_data: # txfile_version_chk for Monero TBD - tx.proto = get_monero_proto(tx, outer_data) + + # TODO: txfile_version_chk for Monero + if self.xmr_data_label in (outer_data := json.loads(data)): + from ..protocol import init_proto + tx.proto = init_proto( + tx.cfg, + 'XMR', + network = outer_data[self.xmr_data_label]['data']['network']) return None + data = outer_data[self.data_label] if outer_data['chksum'] != make_chksum_6(txfile_json_dumps(data)): chk = make_chksum_6(txfile_json_dumps(data)) diff --git a/mmgen/tx/info.py b/mmgen/tx/info.py index ffcf13ca..882f9739 100644 --- a/mmgen/tx/info.py +++ b/mmgen/tx/info.py @@ -27,16 +27,21 @@ class TxInfo: tx = self.tx yield ' {} {}\n'.format(magenta('DEX Protocol:'), blue(tx.swap_proto_mod.name)) yield ' Swap: {}\n'.format(orange(f'{tx.send_asset.name} => {tx.recv_asset.name}')) + recv_addr = None recv_mmid = getattr(tx, 'swap_recv_addr_mmid', None) - if (not tx.is_memoless) or tx.memoless_memo: - data = ( - tx.memoless_memo.encode() if tx.is_memoless else - tx.swap_memo.encode() if tx.proto.is_vm else - tx.data_output.data) + if tx.is_memoless: + if tx.memoless_memo: + recv_addr = tx.swap_proto_mod.Memo.parse(tx.memoless_memo).address + else: + data = tx.swap_memo.encode() if tx.proto.is_vm else tx.data_output.data if tx.swap_proto_mod.Memo.is_partial_memo(data): - yield ' Dest: {}{}\n'.format( - cyan(tx.swap_proto_mod.Memo.parse(data.decode('ascii')).address), - orange(f' {recv_mmid}') if recv_mmid else '') + recv_addr = tx.swap_proto_mod.Memo.parse(data.decode('ascii')).address + yield ' Dest: {a}{b}{c}\n'.format( + a = cyan(recv_addr) if recv_addr else '', + b = ' ' if recv_addr and recv_mmid else '', + c = orange(recv_mmid) if recv_mmid else '') + if tx.is_memoless and tx.refnum: + yield f' Refnum: {tx.refnum.hl()}' if not recv_mmid: yield yellow(' Warning: swap destination address is not a wallet address!\n') diff --git a/mmgen/tx/new_swap.py b/mmgen/tx/new_swap.py index 92c706a6..625f2091 100644 --- a/mmgen/tx/new_swap.py +++ b/mmgen/tx/new_swap.py @@ -13,6 +13,7 @@ tx.new_swap: new swap transaction class import sys, time from collections import namedtuple +from ..obj import PositiveInt from ..addr import CoinAddr from ..amt import UniAmt from ..util import msg, ymsg, is_int, die @@ -36,7 +37,7 @@ class NewSwap(BaseSwapMethods, New): def __init__(self, *, cfg, is_memoless=False, **kwargs): assert is_int(cfg.refnum) or cfg.refnum is None, '--refnum must be an integer' - self.refnum = int(cfg.refnum) if is_int(cfg.refnum) else None + self.refnum = PositiveInt(cfg.refnum) if is_int(cfg.refnum) else None self.swap_proto = cfg.swap_proto self.is_swap = True self.is_memoless = bool(is_memoless) diff --git a/mmgen/xmrwallet/file/__init__.py b/mmgen/xmrwallet/file/__init__.py index 1f5d803b..613320af 100644 --- a/mmgen/xmrwallet/file/__init__.py +++ b/mmgen/xmrwallet/file/__init__.py @@ -53,6 +53,5 @@ class MoneroMMGenFile: 'data': in_data}} def extract_data_from_file(self, cfg, fn): - return json.loads( - get_data_from_file(cfg, str(fn), desc=self.desc, silent=self.silent_load) - )[self.data_label] + data = json.loads(get_data_from_file(cfg, str(fn), desc=self.desc, silent=self.silent_load)) + return data[self.data_label] diff --git a/mmgen/xmrwallet/file/tx.py b/mmgen/xmrwallet/file/tx.py index 7e20d03a..86f7293a 100644 --- a/mmgen/xmrwallet/file/tx.py +++ b/mmgen/xmrwallet/file/tx.py @@ -12,7 +12,6 @@ xmrwallet.file.tx: Monero transaction file class for the MMGen Suite import time from collections import namedtuple -from pathlib import Path from ...obj import CoinTxID, Int from ...color import red, yellow, blue, cyan, pink, orange, purple @@ -267,7 +266,6 @@ class MoneroMMGenTX: super().__init__() self.cfg = cfg - self.fn = Path(fn) try: d_wrap = self.extract_data_from_file(cfg, fn) diff --git a/test/cmdtest_d/misc.py b/test/cmdtest_d/misc.py index a5c4d89c..d6a83ea3 100644 --- a/test/cmdtest_d/misc.py +++ b/test/cmdtest_d/misc.py @@ -68,6 +68,7 @@ class CmdTestMisc(CmdTestBase): ('bch_txview_legacy2', '‘mmgen-tool --coin=bch --cashaddr=0 txview terse=1’'), ('bch_txview_cashaddr1', '‘mmgen-tool --coin=bch --cashaddr=1 txview terse=0’'), ('bch_txview_cashaddr2', '‘mmgen-tool --coin=bch --cashaddr=1 txview terse=1’'), + ('xmr_txview', '‘mmgen-tool txview’ with XMR transactions'), ('xmrwallet_txview', '‘mmgen-xmrwallet txview’'), ('xmrwallet_txlist', '‘mmgen-xmrwallet txlist’'), ('coin_daemon_info', '‘examples/coin-daemon-info.py’'), @@ -104,6 +105,14 @@ class CmdTestMisc(CmdTestBase): def bch_txview_cashaddr2(self): return self._bch_txview(1, 1, '[1HpynST7vkLn8yNtdrqPfeghexZk4sdB3W]') + def xmr_txview(self, tdir='test/ref/monero', ext='asubtx'): + if self.cfg.no_altcoin: + return 'skip' + files = get_file_with_ext(tdir, ext, no_dot=True, delete=False, return_list=True) + t = self.spawn('mmgen-tool', ['txview'] + files) + t.read() + return t + def xmrwallet_txview(self, op='txview'): if self.cfg.no_altcoin: return 'skip' @@ -113,9 +122,8 @@ class CmdTestMisc(CmdTestBase): match op: case 'txview': for s in ( - 'Amount: 0.74 XMR', - 'Dest: 56VQ9M6k', - ): + 'Amount: 0.74 XMR', + 'Dest: 56VQ9M6k'): assert s in res, f'{s} not in {res}' case 'txlist': assert re.search('3EBD06-.*D94583-.*8BFA29-', res, re.DOTALL) diff --git a/test/cmdtest_d/xmrswap.py b/test/cmdtest_d/xmrswap.py index 9551ccf9..c752e5aa 100644 --- a/test/cmdtest_d/xmrswap.py +++ b/test/cmdtest_d/xmrswap.py @@ -57,7 +57,7 @@ class CmdTestXMRSwapMethods: for pat in expect_pats: t.expect(pat, regex=True) t.expect('to continue: ', '\n') - t.expect('(y/N): ', 'y') # save? + t.expect('(y/N): ', 'y') # save? t.written_to_file('Unsigned automount transaction') return t