Browse Source

MMGenTX: code cleanups, variable and method renames

The MMGen Project 3 years ago
parent
commit
ab8028ae64
4 changed files with 106 additions and 87 deletions
  1. 48 35
      mmgen/altcoins/eth/tx.py
  2. 6 6
      mmgen/main_txbump.py
  3. 1 1
      mmgen/opts.py
  4. 51 45
      mmgen/tx.py

+ 48 - 35
mmgen/altcoins/eth/tx.py

@@ -55,8 +55,8 @@ class EthereumMMGenTX:
 		def get_hex_locktime(self):
 		def get_hex_locktime(self):
 			return None # TODO
 			return None # TODO
 
 
-		# given rel fee in wei, return absolute fee using tx_gas (not in MMGenTX)
-		def fee_rel2abs(self,rel_fee):
+		# given rel fee (gasPrice) in wei, return absolute fee using tx_gas (not in MMGenTX)
+		def fee_gasPrice2abs(self,rel_fee):
 			assert isinstance(rel_fee,int),"'{}': incorrect type for fee estimate (not an integer)".format(rel_fee)
 			assert isinstance(rel_fee,int),"'{}': incorrect type for fee estimate (not an integer)".format(rel_fee)
 			return ETHAmt(rel_fee * self.tx_gas.toWei(),'wei')
 			return ETHAmt(rel_fee * self.tx_gas.toWei(),'wei')
 
 
@@ -158,22 +158,25 @@ class EthereumMMGenTX:
 			return Int(await self.rpc.call('eth_gasPrice'),16),'eth_gasPrice' # ==> rel_fee,fe_type
 			return Int(await self.rpc.call('eth_gasPrice'),16),'eth_gasPrice' # ==> rel_fee,fe_type
 
 
 		def check_fee(self):
 		def check_fee(self):
-			assert self.disable_fee_check or (self.fee <= self.proto.max_tx_fee)
+			if not self.disable_fee_check:
+				assert self.usr_fee <= self.proto.max_tx_fee
 
 
 		# given rel fee and units, return absolute fee using tx_gas
 		# given rel fee and units, return absolute fee using tx_gas
-		def convert_fee_spec(self,foo,units,amt,unit):
-			self.usr_rel_fee = ETHAmt(int(amt),units[unit])
-			return ETHAmt(self.usr_rel_fee.toWei() * self.tx_gas.toWei(),'wei')
+		def fee_rel2abs(self,tx_size,units,amt,unit):
+			return ETHAmt(
+				ETHAmt(amt,units[unit]).toWei() * self.tx_gas.toWei(),
+				from_unit='wei'
+			)
 
 
 		# given fee estimate (gas price) in wei, return absolute fee, adjusting by opt.tx_fee_adj
 		# given fee estimate (gas price) in wei, return absolute fee, adjusting by opt.tx_fee_adj
 		def fee_est2abs(self,rel_fee,fe_type=None):
 		def fee_est2abs(self,rel_fee,fe_type=None):
-			ret = self.fee_rel2abs(rel_fee) * opt.tx_fee_adj
+			ret = self.fee_gasPrice2abs(rel_fee) * opt.tx_fee_adj
 			if opt.verbose:
 			if opt.verbose:
 				msg('Estimated fee: {} ETH'.format(ret))
 				msg('Estimated fee: {} ETH'.format(ret))
 			return ret
 			return ret
 
 
 		def convert_and_check_fee(self,tx_fee,desc='Missing description'):
 		def convert_and_check_fee(self,tx_fee,desc='Missing description'):
-			abs_fee = self.process_fee_spec(tx_fee,None)
+			abs_fee = self.feespec2abs(tx_fee,None)
 			if abs_fee == False:
 			if abs_fee == False:
 				return False
 				return False
 			elif not self.disable_fee_check and (abs_fee > self.proto.max_tx_fee):
 			elif not self.disable_fee_check and (abs_fee > self.proto.max_tx_fee):
@@ -183,9 +186,9 @@ class EthereumMMGenTX:
 			else:
 			else:
 				return abs_fee
 				return abs_fee
 
 
-		def update_change_output(self,change_amt):
+		def update_change_output(self,funds_left):
 			if self.outputs and self.outputs[0].is_chg:
 			if self.outputs and self.outputs[0].is_chg:
-				self.update_output_amt(0,ETHAmt(change_amt))
+				self.update_output_amt(0,ETHAmt(funds_left))
 
 
 		def update_send_amt(self):
 		def update_send_amt(self):
 			if self.outputs:
 			if self.outputs:
@@ -212,16 +215,22 @@ class EthereumMMGenTX:
 						die(1,"'{}': not an MMGen ID or coin address".format(i))
 						die(1,"'{}': not an MMGen ID or coin address".format(i))
 			return ret
 			return ret
 
 
-		def final_inputs_ok_msg(self,change_amt):
-			m = "Transaction leaves {} {} in the sender's account"
-			chg = '0' if (self.outputs and self.outputs[0].is_chg) else change_amt
-			return m.format(ETHAmt(chg).hl(),self.proto.coin)
+		def final_inputs_ok_msg(self,funds_left):
+			chg = '0' if (self.outputs and self.outputs[0].is_chg) else funds_left
+			return "Transaction leaves {} {} in the sender's account".format(
+				ETHAmt(chg).hl(),
+				self.proto.coin
+			)
 
 
 	class Completed(Base,MMGenTX.Completed):
 	class Completed(Base,MMGenTX.Completed):
 		fn_fee_unit = 'Mwei'
 		fn_fee_unit = 'Mwei'
 		txview_hdr_fs = 'TRANSACTION DATA\n\nID={i} ({a} {c}) UTC={t} Sig={s} Locktime={l}\n'
 		txview_hdr_fs = 'TRANSACTION DATA\n\nID={i} ({a} {c}) UTC={t} Sig={s} Locktime={l}\n'
 		txview_hdr_fs_short = 'TX {i} ({a} {c}) UTC={t} Sig={s} Locktime={l}\n'
 		txview_hdr_fs_short = 'TX {i} ({a} {c}) UTC={t} Sig={s} Locktime={l}\n'
-		txview_ftr_fs = 'Total in account: {i} {d}\nTotal to spend:   {o} {d}\nTX fee:           {a} {c}{r}\n'
+		txview_ftr_fs = fmt("""
+			Total in account:  {i} {d}
+			Total to spend:    {o} {d}
+			TX fee:            {a} {c}{r}
+		""")
 		fmt_keys = ('from','to','amt','nonce')
 		fmt_keys = ('from','to','amt','nonce')
 
 
 		def check_txfile_hex_data(self):
 		def check_txfile_hex_data(self):
@@ -253,9 +262,8 @@ class EthereumMMGenTX:
 				f_mmid = m['inputs'] )
 				f_mmid = m['inputs'] )
 
 
 		def format_view_abs_fee(self):
 		def format_view_abs_fee(self):
-			fee = self.fee_rel2abs(self.txobj['gasPrice'].toWei())
-			note = ' (max)' if self.txobj['data'] else ''
-			return fee.hl() + note
+			fee = self.fee_gasPrice2abs(self.txobj['gasPrice'].toWei())
+			return fee.hl() + (' (max)' if self.txobj['data'] else '')
 
 
 		def format_view_rel_fee(self,terse):
 		def format_view_rel_fee(self,terse):
 			return ''
 			return ''
@@ -292,7 +300,7 @@ class EthereumMMGenTX:
 				'chainId':  Int(d['chainId']),
 				'chainId':  Int(d['chainId']),
 				'data':     HexStr(d['data']) }
 				'data':     HexStr(d['data']) }
 			self.tx_gas = o['startGas'] # approximate, but better than nothing
 			self.tx_gas = o['startGas'] # approximate, but better than nothing
-			self.fee = self.fee_rel2abs(o['gasPrice'].toWei())
+			self.fee = self.fee_gasPrice2abs(o['gasPrice'].toWei())
 			self.txobj = o
 			self.txobj = o
 			return d # 'token_addr','decimals' required by Token subclass
 			return d # 'token_addr','decimals' required by Token subclass
 
 
@@ -371,7 +379,7 @@ class EthereumMMGenTX:
 			txid = CoinTxID(etx.hash.hex())
 			txid = CoinTxID(etx.hash.hex())
 			assert txid == self.coin_txid,"txid in tx.hex doesn't match value in MMGen transaction file"
 			assert txid == self.coin_txid,"txid in tx.hex doesn't match value in MMGen transaction file"
 			self.tx_gas = o['startGas'] # approximate, but better than nothing
 			self.tx_gas = o['startGas'] # approximate, but better than nothing
-			self.fee = self.fee_rel2abs(o['gasPrice'].toWei())
+			self.fee = self.fee_gasPrice2abs(o['gasPrice'].toWei())
 			self.txobj = o
 			self.txobj = o
 			return d # 'token_addr','decimals' required by Token subclass
 			return d # 'token_addr','decimals' required by Token subclass
 
 
@@ -413,7 +421,7 @@ class EthereumMMGenTX:
 
 
 			self.check_correct_chain()
 			self.check_correct_chain()
 
 
-			fee = self.fee_rel2abs(self.txobj['gasPrice'].toWei())
+			fee = self.fee_gasPrice2abs(self.txobj['gasPrice'].toWei())
 
 
 			if not self.disable_fee_check and (fee > self.proto.max_tx_fee):
 			if not self.disable_fee_check and (fee > self.proto.max_tx_fee):
 				die(2,'Transaction fee ({}) greater than {} max_tx_fee ({} {})!'.format(
 				die(2,'Transaction fee ({}) greater than {} max_tx_fee ({} {})!'.format(
@@ -463,7 +471,7 @@ class EthereumMMGenTX:
 		def min_fee(self):
 		def min_fee(self):
 			return ETHAmt(self.fee * Decimal('1.101'))
 			return ETHAmt(self.fee * Decimal('1.101'))
 
 
-		def update_fee(self,foo,fee):
+		def bump_fee(self,idx,fee):
 			self.fee = fee
 			self.fee = fee
 
 
 		async def get_nonce(self):
 		async def get_nonce(self):
@@ -489,28 +497,33 @@ class EthereumTokenMMGenTX:
 			o['token_to'] = o['to']
 			o['token_to'] = o['to']
 			o['data'] = t.create_data(o['token_to'],o['amt'])
 			o['data'] = t.create_data(o['token_to'],o['amt'])
 
 
-		def update_change_output(self,change_amt):
+		def update_change_output(self,funds_left):
 			if self.outputs[0].is_chg:
 			if self.outputs[0].is_chg:
 				self.update_output_amt(0,self.inputs[0].amt)
 				self.update_output_amt(0,self.inputs[0].amt)
 
 
 		# token transaction, so check both eth and token balances
 		# token transaction, so check both eth and token balances
 		# TODO: add test with insufficient funds
 		# TODO: add test with insufficient funds
-		async def precheck_sufficient_funds(self,inputs_sum,sel_unspent):
+		async def precheck_sufficient_funds(self,inputs_sum,sel_unspent,outputs_sum):
 			eth_bal = await self.tw.get_eth_balance(sel_unspent[0].addr)
 			eth_bal = await self.tw.get_eth_balance(sel_unspent[0].addr)
 			if eth_bal == 0: # we don't know the fee yet
 			if eth_bal == 0: # we don't know the fee yet
 				msg('This account has no ether to pay for the transaction fee!')
 				msg('This account has no ether to pay for the transaction fee!')
 				return False
 				return False
-			return await super().precheck_sufficient_funds(inputs_sum,sel_unspent)
-
-		async def get_change_amt(self): # here we know the fee
-			eth_bal = await self.tw.get_eth_balance(self.inputs[0].addr)
-			return eth_bal - self.fee
-
-		def final_inputs_ok_msg(self,change_amt):
-			token_bal   = ( ETHAmt('0') if self.outputs[0].is_chg else
-							self.inputs[0].amt - self.outputs[0].amt )
-			m = "Transaction leaves ≈{} {} and {} {} in the sender's account"
-			return m.format( change_amt.hl(), self.proto.coin, token_bal.hl(), self.proto.dcoin )
+			return await super().precheck_sufficient_funds(inputs_sum,sel_unspent,outputs_sum)
+
+		async def get_funds_left(self,fee,outputs_sum):
+			return ( await self.tw.get_eth_balance(self.inputs[0].addr) ) - fee
+
+		def final_inputs_ok_msg(self,funds_left):
+			token_bal = (
+				ETHAmt('0') if self.outputs[0].is_chg
+				else self.inputs[0].amt - self.outputs[0].amt
+			)
+			return "Transaction leaves ≈{} {} and {} {} in the sender's account".format(
+				funds_left.hl(),
+				self.proto.coin,
+				token_bal.hl(),
+				self.proto.dcoin
+			)
 
 
 	class Completed(Base,EthereumMMGenTX.Completed):
 	class Completed(Base,EthereumMMGenTX.Completed):
 		fmt_keys = ('from','token_to','amt','nonce')
 		fmt_keys = ('from','token_to','amt','nonce')

+ 6 - 6
mmgen/main_txbump.py

@@ -140,22 +140,22 @@ async def main():
 	from .rpc import rpc_init
 	from .rpc import rpc_init
 	tx.rpc = await rpc_init(tx.proto)
 	tx.rpc = await rpc_init(tx.proto)
 
 
-	tx.check_bumpable() # needs cached networkinfo['relayfee']
-
 	msg('Creating replacement transaction')
 	msg('Creating replacement transaction')
 
 
-	op_idx = tx.choose_output()
+	tx.check_sufficient_funds_for_bump()
+
+	output_idx = tx.choose_output()
 
 
 	if not silent:
 	if not silent:
 		msg('Minimum fee for new transaction: {} {}'.format(tx.min_fee.hl(),tx.proto.coin))
 		msg('Minimum fee for new transaction: {} {}'.format(tx.min_fee.hl(),tx.proto.coin))
 
 
-	fee = tx.get_usr_fee_interactive(tx_fee=opt.tx_fee,desc='User-selected')
+	tx.usr_fee = tx.get_usr_fee_interactive(tx_fee=opt.tx_fee,desc='User-selected')
 
 
-	tx.update_fee(op_idx,fee)
+	tx.bump_fee(output_idx,tx.usr_fee)
 	tx.update_send_amt()
 	tx.update_send_amt()
 
 
 	d = tx.get_fee()
 	d = tx.get_fee()
-	assert d == fee and d <= tx.proto.max_tx_fee
+	assert d == tx.usr_fee and d <= tx.proto.max_tx_fee
 
 
 	if tx.proto.base_proto == 'Bitcoin':
 	if tx.proto.base_proto == 'Bitcoin':
 		tx.outputs.sort_bip69() # output amts have changed, so re-sort
 		tx.outputs.sort_bip69() # output amts have changed, so re-sort

+ 1 - 1
mmgen/opts.py

@@ -405,7 +405,7 @@ def opt_is_tx_fee(key,val,desc): # 'key' must remain a placeholder
 	tx = MMGenTX.New(init_proto_from_opts())
 	tx = MMGenTX.New(init_proto_from_opts())
 	# Size of 224 is just a ball-park figure to eliminate the most extreme cases at startup
 	# Size of 224 is just a ball-park figure to eliminate the most extreme cases at startup
 	# This check will be performed again once we know the true size
 	# This check will be performed again once we know the true size
-	ret = tx.process_fee_spec(val,224)
+	ret = tx.feespec2abs(val,224)
 
 
 	if ret == False:
 	if ret == False:
 		raise UserOptError('{!r}: invalid {}\n(not a {} amount or {} specification)'.format(
 		raise UserOptError('{!r}: invalid {}\n(not a {} amount or {} specification)'.format(

+ 51 - 45
mmgen/tx.py

@@ -576,10 +576,12 @@ class MMGenTX:
 			return fee_per_kb,fe_type
 			return fee_per_kb,fe_type
 
 
 		# given tx size, rel fee and units, return absolute fee
 		# given tx size, rel fee and units, return absolute fee
-		def convert_fee_spec(self,tx_size,units,amt,unit):
+		def fee_rel2abs(self,tx_size,units,amt,unit):
 			self.usr_rel_fee = None # TODO
 			self.usr_rel_fee = None # TODO
-			return self.proto.coin_amt(int(amt)*tx_size*getattr(self.proto.coin_amt,units[unit])) \
-				if tx_size else None
+			if tx_size:
+				return self.proto.coin_amt(amt * tx_size * getattr(self.proto.coin_amt,units[unit]))
+			else:
+				return None
 
 
 		# given network fee estimate in BTC/kB, return absolute fee using estimated tx size
 		# given network fee estimate in BTC/kB, return absolute fee using estimated tx size
 		def fee_est2abs(self,fee_per_kb,fe_type=None):
 		def fee_est2abs(self,fee_per_kb,fe_type=None):
@@ -596,7 +598,7 @@ class MMGenTX:
 			return ret
 			return ret
 
 
 		def convert_and_check_fee(self,tx_fee,desc='Missing description'):
 		def convert_and_check_fee(self,tx_fee,desc='Missing description'):
-			abs_fee = self.process_fee_spec(tx_fee,self.estimate_size())
+			abs_fee = self.feespec2abs(tx_fee,self.estimate_size())
 			if abs_fee == None:
 			if abs_fee == None:
 				raise ValueError(f'{tx_fee}: cannot convert {self.rel_fee_desc} to {self.coin}'
 				raise ValueError(f'{tx_fee}: cannot convert {self.rel_fee_desc} to {self.coin}'
 									+ ' because transaction size is unknown')
 									+ ' because transaction size is unknown')
@@ -615,7 +617,7 @@ class MMGenTX:
 
 
 		# given tx size and absolute fee or fee spec, return absolute fee
 		# given tx size and absolute fee or fee spec, return absolute fee
 		# relative fee is N+<first letter of unit name>
 		# relative fee is N+<first letter of unit name>
-		def process_fee_spec(self,tx_fee,tx_size):
+		def feespec2abs(self,tx_fee,tx_size):
 			fee = get_obj(self.proto.coin_amt,num=tx_fee,silent=True)
 			fee = get_obj(self.proto.coin_amt,num=tx_fee,silent=True)
 			if fee:
 			if fee:
 				return fee
 				return fee
@@ -625,7 +627,7 @@ class MMGenTX:
 				pat = re.compile(r'([1-9][0-9]*)({})'.format('|'.join(units)))
 				pat = re.compile(r'([1-9][0-9]*)({})'.format('|'.join(units)))
 				if pat.match(tx_fee):
 				if pat.match(tx_fee):
 					amt,unit = pat.match(tx_fee).groups()
 					amt,unit = pat.match(tx_fee).groups()
-					return self.convert_fee_spec(tx_size,units,amt,unit)
+					return self.fee_rel2abs(tx_size,units,int(amt),unit)
 			return False
 			return False
 
 
 		def get_usr_fee_interactive(self,tx_fee=None,desc='Starting'):
 		def get_usr_fee_interactive(self,tx_fee=None,desc='Starting'):
@@ -769,12 +771,12 @@ class MMGenTX:
 			return set(get_uo_nums()) # silently discard duplicates
 			return set(get_uo_nums()) # silently discard duplicates
 
 
 		# we don't know fee yet, so perform preliminary check with fee == 0
 		# we don't know fee yet, so perform preliminary check with fee == 0
-		async def precheck_sufficient_funds(self,inputs_sum,sel_unspent):
-			if self.twuo.total < self.send_amt:
-				msg(self.msg_wallet_low_coin.format(self.send_amt-inputs_sum,self.dcoin))
+		async def precheck_sufficient_funds(self,inputs_sum,sel_unspent,outputs_sum):
+			if self.twuo.total < outputs_sum:
+				msg(self.msg_wallet_low_coin.format(outputs_sum-inputs_sum,self.dcoin))
 				return False
 				return False
-			if inputs_sum < self.send_amt:
-				msg(self.msg_low_coin.format(self.send_amt-inputs_sum,self.dcoin))
+			if inputs_sum < outputs_sum:
+				msg(self.msg_low_coin.format(outputs_sum-inputs_sum,self.dcoin))
 				return False
 				return False
 			return True
 			return True
 
 
@@ -789,16 +791,19 @@ class MMGenTX:
 					yield i
 					yield i
 			self.inputs = MMGenTxInputList(self,list(gen_inputs()))
 			self.inputs = MMGenTxInputList(self,list(gen_inputs()))
 
 
-		async def get_change_amt(self):
-			return self.sum_inputs() - self.send_amt - self.fee
+		async def get_funds_left(self,fee,outputs_sum):
+			return self.sum_inputs() - outputs_sum - fee
 
 
-		def final_inputs_ok_msg(self,change_amt):
-			return f'Transaction produces {self.proto.coin_amt(change_amt).hl()} {self.coin} in change'
+		def final_inputs_ok_msg(self,funds_left):
+			return 'Transaction produces {} {} in change'.format(
+				self.proto.coin_amt(funds_left).hl(),
+				self.coin
+			)
 
 
-		def warn_insufficient_chg(self,change_amt):
-			msg(self.msg_low_coin.format(self.proto.coin_amt(-change_amt).hl(),self.coin))
+		def warn_insufficient_funds(self,funds_left):
+			msg(self.msg_low_coin.format(self.proto.coin_amt(-funds_left).hl(),self.coin))
 
 
-		async def get_inputs_from_user(self):
+		async def get_inputs_from_user(self,outputs_sum):
 
 
 			while True:
 			while True:
 				us_f = self.select_unspent_cmdline if opt.inputs else self.select_unspent
 				us_f = self.select_unspent_cmdline if opt.inputs else self.select_unspent
@@ -808,31 +813,31 @@ class MMGenTX:
 				sel_unspent = self.twuo.MMGenTwOutputList([self.twuo.unspent[i-1] for i in sel_nums])
 				sel_unspent = self.twuo.MMGenTwOutputList([self.twuo.unspent[i-1] for i in sel_nums])
 
 
 				inputs_sum = sum(s.amt for s in sel_unspent)
 				inputs_sum = sum(s.amt for s in sel_unspent)
-				if not await self.precheck_sufficient_funds(inputs_sum,sel_unspent):
+				if not await self.precheck_sufficient_funds(inputs_sum,sel_unspent,outputs_sum):
 					continue
 					continue
 
 
 				self.copy_inputs_from_tw(sel_unspent)  # makes self.inputs
 				self.copy_inputs_from_tw(sel_unspent)  # makes self.inputs
 
 
-				self.fee = await self.get_fee_from_user()
+				self.usr_fee = await self.get_fee_from_user()
 
 
-				change_amt = await self.get_change_amt()
+				funds_left = await self.get_funds_left(self.usr_fee,outputs_sum)
 
 
-				if change_amt >= 0:
-					p = self.final_inputs_ok_msg(change_amt)
+				if funds_left >= 0:
+					p = self.final_inputs_ok_msg(funds_left)
 					if opt.yes or keypress_confirm(p+'. OK?',default_yes=True):
 					if opt.yes or keypress_confirm(p+'. OK?',default_yes=True):
 						if opt.yes:
 						if opt.yes:
 							msg(p)
 							msg(p)
-						return change_amt
+						return funds_left
 				else:
 				else:
-					self.warn_insufficient_chg(change_amt)
+					self.warn_insufficient_funds(funds_left)
 
 
-		def update_change_output(self,change_amt):
+		def update_change_output(self,funds_left):
 			chg_idx = self.get_chg_output_idx()
 			chg_idx = self.get_chg_output_idx()
-			if change_amt == 0:
+			if funds_left == 0:
 				msg(self.no_chg_msg)
 				msg(self.no_chg_msg)
 				self.del_output(chg_idx)
 				self.del_output(chg_idx)
 			else:
 			else:
-				self.update_output_amt(chg_idx,self.proto.coin_amt(change_amt))
+				self.update_output_amt(chg_idx,self.proto.coin_amt(funds_left))
 
 
 		def update_send_amt(self):
 		def update_send_amt(self):
 			self.send_amt = self.sum_outputs(exclude =
 			self.send_amt = self.sum_outputs(exclude =
@@ -884,17 +889,17 @@ class MMGenTX:
 				del self.twuo.wallet
 				del self.twuo.wallet
 				sys.exit(0)
 				sys.exit(0)
 
 
-			self.send_amt = self.sum_outputs()
+			outputs_sum = self.sum_outputs()
 
 
-			msg_r('Total amount to spend: ')
-			msg(f'{self.send_amt.hl()} {self.dcoin}' if self.send_amt else 'Unknown')
+			msg('Total amount to spend: {}'.format(
+				f'{outputs_sum.hl()} {self.dcoin}' if outputs_sum else 'Unknown'
+			))
 
 
-			change_amt = await self.get_inputs_from_user()
+			funds_left = await self.get_inputs_from_user(outputs_sum)
 
 
 			self.check_non_mmgen_inputs(caller)
 			self.check_non_mmgen_inputs(caller)
 
 
-			self.update_change_output(change_amt)
-			self.update_send_amt()
+			self.update_change_output(funds_left)
 
 
 			if self.proto.base_proto == 'Bitcoin':
 			if self.proto.base_proto == 'Bitcoin':
 				self.inputs.sort_bip69()
 				self.inputs.sort_bip69()
@@ -942,8 +947,8 @@ class MMGenTX:
 		txview_hdr_fs_short = 'TX {i} ({a} {c}) UTC={t} RBF={r} Sig={s} Locktime={l}\n'
 		txview_hdr_fs_short = 'TX {i} ({a} {c}) UTC={t} RBF={r} Sig={s} Locktime={l}\n'
 		txview_ftr_fs = fmt("""
 		txview_ftr_fs = fmt("""
 			Input amount: {i} {d}
 			Input amount: {i} {d}
-			Change:       {C} {d}
 			Spend amount: {s} {d}
 			Spend amount: {s} {d}
+			Change:       {C} {d}
 			Fee:          {a} {c}{r}
 			Fee:          {a} {c}{r}
 		""")
 		""")
 		parsed_hex = None
 		parsed_hex = None
@@ -1497,7 +1502,7 @@ class MMGenTX:
 
 
 			self.coin_txid = ''
 			self.coin_txid = ''
 
 
-		def check_bumpable(self):
+		def check_sufficient_funds_for_bump(self):
 			if not [o.amt for o in self.outputs if o.amt >= self.min_fee]:
 			if not [o.amt for o in self.outputs if o.amt >= self.min_fee]:
 				die(1,
 				die(1,
 					'Transaction cannot be bumped.\n' +
 					'Transaction cannot be bumped.\n' +
@@ -1549,9 +1554,11 @@ class MMGenTX:
 		def min_fee(self):
 		def min_fee(self):
 			return self.sum_inputs() - self.sum_outputs() + self.relay_fee
 			return self.sum_inputs() - self.sum_outputs() + self.relay_fee
 
 
-		def update_fee(self,op_idx,fee):
-			amt = self.sum_inputs() - self.sum_outputs(exclude=op_idx) - fee
-			self.update_output_amt(op_idx,amt)
+		def bump_fee(self,idx,fee):
+			self.update_output_amt(
+				idx,
+				self.sum_inputs() - self.sum_outputs(exclude=idx) - fee
+			)
 
 
 		def convert_and_check_fee(self,tx_fee,desc):
 		def convert_and_check_fee(self,tx_fee,desc):
 			ret = super().convert_and_check_fee(tx_fee,desc)
 			ret = super().convert_and_check_fee(tx_fee,desc)
@@ -1607,18 +1614,17 @@ class MMGenTX:
 #			await self.get_outputs_from_cmdline(mmid)
 #			await self.get_outputs_from_cmdline(mmid)
 #
 #
 #			while True:
 #			while True:
-#				change_amt = self.sum_inputs() - self.get_split_fee_from_user()
-#				if change_amt >= 0:
-#					p = 'Transaction produces {} {} in change'.format(change_amt.hl(),self.coin)
+#				funds_left = self.sum_inputs() - self.get_split_fee_from_user()
+#				if funds_left >= 0:
+#					p = 'Transaction produces {} {} in change'.format(funds_left.hl(),self.coin)
 #					if opt.yes or keypress_confirm(p+'.  OK?',default_yes=True):
 #					if opt.yes or keypress_confirm(p+'.  OK?',default_yes=True):
 #						if opt.yes:
 #						if opt.yes:
 #							msg(p)
 #							msg(p)
 #						break
 #						break
 #				else:
 #				else:
-#					self.warn_insufficient_chg(change_amt)
+#					self.warn_insufficient_funds(funds_left)
 #
 #
-#			self.update_output_amt(0,change_amt)
-#			self.send_amt = change_amt
+#			self.update_output_amt(0,funds_left)
 #
 #
 #			if not opt.yes:
 #			if not opt.yes:
 #				self.add_comment()  # edits an existing comment
 #				self.add_comment()  # edits an existing comment