From d9e244942913e9075b27f287e90991b253d3b197 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Thu, 15 Oct 2026 09:35:53 +0000 Subject: [PATCH] tx: allow zero send amount for deposit transactions (bugfix) Fixes a critical bug whereby the memoless registration transaction spent all the RUNE in the account. Note that memoless swaps are enabled in the test suite only, so the bug could not have led to loss of user funds. As an added safeguard, the patch also disables zero send amounts for non-deposit transactions. --- mmgen/data/version | 2 +- mmgen/tx/new.py | 6 +++++- test/cmdtest_d/rune.py | 3 +++ test/cmdtest_d/swap.py | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index c572c533..55808c92 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -16.3.0dev16 +16.3.0dev17 diff --git a/mmgen/tx/new.py b/mmgen/tx/new.py index 61c4dd4a..0ef5e359 100644 --- a/mmgen/tx/new.py +++ b/mmgen/tx/new.py @@ -189,6 +189,9 @@ class New(Base): amt = self.proto.coin_amt(amt_in or '0') + if not (amt or amt_in is None or self.is_deposit): + die(2, 'For non-deposit transactions, amount must be nonzero') + coin_addr, mmid, is_vault = (None, None, False) if (arg == 'vault' and self.is_swap) or (arg == 'deposit' and self.is_deposit): @@ -543,7 +546,8 @@ class New(Base): if not self.is_compat: self.check_non_mmgen_inputs(caller=caller) - self.update_change_output(funds_left) + if not self.is_deposit: + self.update_change_output(funds_left) if self.is_memoless and self.refnum: self.update_vault_memoless_amt(round_down=len(self.outputs) == 1) self.check_chg_addr_is_wallet_addr() diff --git a/test/cmdtest_d/rune.py b/test/cmdtest_d/rune.py index c5373c15..9d4b8af1 100644 --- a/test/cmdtest_d/rune.py +++ b/test/cmdtest_d/rune.py @@ -40,6 +40,7 @@ class CmdTestRuneMethods: args = ['98831F3A:X:2,54.321'], add_opts = [], append_args = [], + expect_pat = None, menu_prompt = None): t = self.spawn('mmgen-txcreate', self.rune_opts + add_opts + args + append_args) t.expect(menu_prompt or self.menu_prompt, 'q') @@ -47,6 +48,8 @@ class CmdTestRuneMethods: t.expect('(y/N): ', 'y') # add comment? t.expect('Comment: ', 'THOR Chad #1\n') t.expect('view: ', 'y') + if expect_pat: + t.expect(expect_pat, regex=True) t.expect('to continue: ', 'z') t.expect('(y/N): ', 'y') # save? t.written_to_file('Unsigned transaction') diff --git a/test/cmdtest_d/swap.py b/test/cmdtest_d/swap.py index 2e3c071a..b8a9ab29 100644 --- a/test/cmdtest_d/swap.py +++ b/test/cmdtest_d/swap.py @@ -854,6 +854,7 @@ class CmdTestSwap( return self._rune_txcreate( args = ['deposit,0', f'data:{memo}'], add_opts = ['--coin=rune', '--fee=0.2'], + expect_pat = r'to spend:.*\b0\b.*RUNE', menu_prompt = self.rune_menu_prompt) def rune_txsign_refreq(self):