Browse Source

tx.New: improve command line parsing

The MMGen Project 1 year ago
parent
commit
bf280c7fe4
2 changed files with 46 additions and 29 deletions
  1. 6 1
      mmgen/proto/eth/tx/new.py
  2. 40 28
      mmgen/tx/new.py

+ 6 - 1
mmgen/proto/eth/tx/new.py

@@ -88,7 +88,12 @@ class New(Base,TxBase.New):
 		if lc != 1:
 			die(1, f'{lc} output{suf(lc)} specified, but Ethereum transactions must have exactly one')
 
-		await self.process_cmd_arg(cmd_args[0],ad_f,ad_w)
+		arg = self.parse_cmd_arg(cmd_args[0], ad_f, ad_w)
+
+		self.add_output(
+			coinaddr = arg.coin_addr,
+			amt      = self.proto.coin_amt(arg.amt or '0'),
+			is_chg   = not arg.amt)
 
 	def select_unspent(self,unspent):
 		from ....ui import line_input

+ 40 - 28
mmgen/tx/new.py

@@ -12,6 +12,8 @@
 tx.new: new transaction class
 """
 
+from collections import namedtuple
+
 from .base import Base
 from ..cfg import gc
 from ..color import pink,yellow
@@ -175,50 +177,60 @@ class New(Base):
 	def add_output(self,coinaddr,amt,is_chg=None):
 		self.outputs.append(self.Output(self.proto,addr=coinaddr,amt=amt,is_chg=is_chg))
 
-	async def process_cmd_arg(self,arg_in,ad_f,ad_w):
+	def parse_cmd_arg(self, arg_in, ad_f, ad_w):
+
+		_pa = namedtuple('parsed_txcreate_cmdline_arg', ['arg', 'coin_addr', 'amt'])
 
-		arg,amt = arg_in.split(',',1) if ',' in arg_in else (arg_in,None)
+		arg, amt = arg_in.split(',', 1) if ',' in arg_in else (arg_in, None)
 
-		if is_mmgen_id(self.proto,arg):
-			coin_addr = mmaddr2coinaddr(self.cfg,arg,ad_w,ad_f,self.proto)
-		elif is_coin_addr(self.proto,arg):
-			coin_addr = CoinAddr(self.proto,arg)
-		elif is_mmgen_addrtype(self.proto,arg) or is_addrlist_id(self.proto,arg):
+		if is_mmgen_id(self.proto, arg):
+			coin_addr = mmaddr2coinaddr(self.cfg, arg, ad_w, ad_f, self.proto)
+		elif is_coin_addr(self.proto, arg):
+			coin_addr = CoinAddr(self.proto, arg)
+		elif is_mmgen_addrtype(self.proto, arg) or is_addrlist_id(self.proto, arg):
 			if self.proto.base_proto_coin != 'BTC':
-				die(2,f'Change addresses not supported for {self.proto.name} protocol')
+				die(2, f'Change addresses not supported for {self.proto.name} protocol')
+			self.chg_autoselected = True
+			coin_addr = None
+		else:
+			die(2, f'{arg_in}: invalid command-line argument')
+
+		return _pa(arg, coin_addr, amt)
+
+	async def process_cmd_args(self,cmd_args,ad_f,ad_w):
 
+		async def get_autochg_addr(arg):
 			from ..tw.addresses import TwAddresses
-			al = await TwAddresses(self.cfg,self.proto,get_data=True)
+			al = await TwAddresses(self.cfg, self.proto, get_data=True)
 
-			if is_mmgen_addrtype(self.proto,arg):
-				arg = MMGenAddrType(self.proto,arg)
-				res = al.get_change_address_by_addrtype(arg)
+			if is_mmgen_addrtype(self.proto, arg):
+				res = al.get_change_address_by_addrtype(MMGenAddrType(self.proto, arg))
 				desc = 'of address type'
 			else:
 				res = al.get_change_address(arg)
 				desc = 'from address list'
 
 			if res:
-				coin_addr = res.addr
-				self.chg_autoselected = True
-			else:
-				die(2,'Tracking wallet contains no {t}addresses {d} {a!r}'.format(
-					t = ('unused ','')[res is None],
-					d = desc,
-					a = arg ))
-		else:
-			die(2,f'{arg_in}: invalid command-line argument')
+				return res
 
-		if not (amt or self.chg_idx is None):
-			die(2,'ERROR: More than one change address {} on command line'.format(
-				'requested' if self.chg_autoselected else 'listed'))
+			die(2,'Tracking wallet contains no {t}addresses {d} {a!r}'.format(
+				t = '' if res is None else 'unused ',
+				d = desc,
+				a = arg))
 
-		self.add_output(coin_addr,self.proto.coin_amt(amt or '0'),is_chg=not amt)
+		parsed_args = [self.parse_cmd_arg(a, ad_f, ad_w) for a in cmd_args]
 
-	async def process_cmd_args(self,cmd_args,ad_f,ad_w):
+		chg_args = [a for a in parsed_args if not (a.amt and a.coin_addr)]
+
+		if len(chg_args) > 1:
+			desc = 'requested' if self.chg_autoselected else 'listed'
+			die(2, f'ERROR: More than one change address {desc} on command line')
 
-		for a in cmd_args:
-			await self.process_cmd_arg(a,ad_f,ad_w)
+		for a in parsed_args:
+			self.add_output(
+				coinaddr = a.coin_addr or (await get_autochg_addr(a.arg)).addr,
+				amt      = self.proto.coin_amt(a.amt or '0'),
+				is_chg   = not a.amt)
 
 		if self.chg_idx is None:
 			die(2,