Browse Source

proto.eth.tx: make `self.gas` an integer

The MMGen Project 7 months ago
parent
commit
8d33c6d4a9

+ 2 - 1
mmgen/main_txcreate.py

@@ -57,7 +57,8 @@ opts_data = {
 			+                        {fu} (an integer followed by {fl}).
 			+                        {fu} (an integer followed by {fl}).
 			+                        See FEE SPECIFICATION below.  If omitted, fee will be
 			+                        See FEE SPECIFICATION below.  If omitted, fee will be
 			+                        calculated using network fee estimation.
 			+                        calculated using network fee estimation.
-			e- -g, --gas=         g  Specify start gas amount in Wei
+			et -g, --gas=N           Specify gas limit (integer)
+			-s -g, --gas=N           Specify gas limit for Ethereum (integer)
 			-- -i, --info            Display {a_info} and exit
 			-- -i, --info            Display {a_info} and exit
 			-- -I, --inputs=      i  Specify transaction inputs (comma-separated list of
 			-- -I, --inputs=      i  Specify transaction inputs (comma-separated list of
 			+                        MMGen IDs or coin addresses).  Note that ALL unspent
 			+                        MMGen IDs or coin addresses).  Note that ALL unspent

+ 2 - 1
mmgen/main_txdo.py

@@ -57,7 +57,8 @@ opts_data = {
 			+                         {fu} (an integer followed by {fl!r}).
 			+                         {fu} (an integer followed by {fl!r}).
 			+                         See FEE SPECIFICATION below.  If omitted, fee will be
 			+                         See FEE SPECIFICATION below.  If omitted, fee will be
 			+                         calculated using network fee estimation.
 			+                         calculated using network fee estimation.
-			e- -g, --gas=           g Specify start gas amount in Wei
+			et -g, --gas=N            Specify gas limit (integer)
+			-s -g, --gas=N            Specify gas limit for Ethereum (integer)
 			-- -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
 			-- -H, --hidden-incog-input-params=f,o  Read hidden incognito data from file
 			+                        'f' at offset 'o' (comma-separated)
 			+                        'f' at offset 'o' (comma-separated)
 			-- -i, --in-fmt=        f Input is from wallet format 'f' (see FMT CODES below)
 			-- -i, --in-fmt=        f Input is from wallet format 'f' (see FMT CODES below)

+ 2 - 1
mmgen/proto/eth/contract.py

@@ -67,9 +67,10 @@ class Contract:
 			return ret
 			return ret
 
 
 	def make_tx_in(self, *, gas, gasPrice, nonce, data):
 	def make_tx_in(self, *, gas, gasPrice, nonce, data):
+		assert isinstance(gas, int), f'{type(gas)}: incorrect type for ‘gas’ (must be an int)'
 		return {
 		return {
 			'to':       bytes.fromhex(self.addr),
 			'to':       bytes.fromhex(self.addr),
-			'startgas': gas.toWei(),
+			'startgas': gas,
 			'gasprice': gasPrice.toWei(),
 			'gasprice': gasPrice.toWei(),
 			'value':    0,
 			'value':    0,
 			'nonce':    nonce,
 			'nonce':    nonce,

+ 2 - 2
mmgen/proto/eth/tx/base.py

@@ -44,12 +44,12 @@ class Base(TxBase):
 
 
 	# given absolute fee in ETH, return gas price in ETH
 	# given absolute fee in ETH, return gas price in ETH
 	def fee_abs2gasprice(self, abs_fee):
 	def fee_abs2gasprice(self, abs_fee):
-		return self.proto.coin_amt(int(abs_fee.toWei() // self.gas.toWei()), from_unit='wei')
+		return self.proto.coin_amt(int(abs_fee.toWei() // self.gas), from_unit='wei')
 
 
 	# given rel fee (gasPrice) in wei, return absolute fee using self.gas (Ethereum-only method)
 	# given rel fee (gasPrice) in wei, return absolute fee using self.gas (Ethereum-only method)
 	def fee_gasPrice2abs(self, rel_fee):
 	def fee_gasPrice2abs(self, rel_fee):
 		assert isinstance(rel_fee, int), f'{rel_fee!r}: incorrect type for fee estimate (not an integer)'
 		assert isinstance(rel_fee, int), f'{rel_fee!r}: incorrect type for fee estimate (not an integer)'
-		return self.proto.coin_amt(rel_fee * self.gas.toWei(), from_unit='wei')
+		return self.proto.coin_amt(rel_fee * self.gas, from_unit='wei')
 
 
 	def is_replaceable(self):
 	def is_replaceable(self):
 		return True
 		return True

+ 2 - 1
mmgen/proto/eth/tx/info.py

@@ -16,6 +16,7 @@ from ....tx.info import TxInfo
 from ....util import fmt, pp_fmt
 from ....util import fmt, pp_fmt
 from ....color import yellow, blue, cyan, pink
 from ....color import yellow, blue, cyan, pink
 from ....addr import MMGenID
 from ....addr import MMGenID
+from ....obj import Int
 
 
 class TxInfo(TxInfo):
 class TxInfo(TxInfo):
 	txinfo_hdr_fs = '{hdr}\n  ID={i} ({a} {c}) Sig={s} Locktime={l}\n'
 	txinfo_hdr_fs = '{hdr}\n  ID={i} ({a} {c}) Sig={s} Locktime={l}\n'
@@ -56,7 +57,7 @@ class TxInfo(TxInfo):
 			m      = pink(tx.swap_memo) if tx.is_swap else None,
 			m      = pink(tx.swap_memo) if tx.is_swap else None,
 			c      = tx.proto.dcoin if len(tx.outputs) else '',
 			c      = tx.proto.dcoin if len(tx.outputs) else '',
 			g      = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
 			g      = yellow(tx.pretty_fmt_fee(t['gasPrice'].to_unit('Gwei'))),
-			G      = yellow(tx.pretty_fmt_fee(t['startGas'].to_unit('Kwei'))),
+			G      = Int(t['startGas']).hl(),
 			f_mmid = mmid_disp(tx.inputs[0]),
 			f_mmid = mmid_disp(tx.inputs[0]),
 			t_mmid = mmid_disp(tx.outputs[0]) if tx.outputs and not tx.is_swap else '') + '\n\n'
 			t_mmid = mmid_disp(tx.outputs[0]) if tx.outputs and not tx.is_swap else '') + '\n\n'
 
 

+ 4 - 7
mmgen/proto/eth/tx/new.py

@@ -35,10 +35,7 @@ class New(Base, TxBase.New):
 
 
 		super().__init__(*args, **kwargs)
 		super().__init__(*args, **kwargs)
 
 
-		if self.cfg.gas:
-			self.gas = self.proto.coin_amt(int(self.cfg.gas), from_unit='wei')
-		else:
-			self.gas = self.proto.coin_amt(self.dfl_gas, from_unit='wei')
+		self.gas = int(self.cfg.gas or self.dfl_gas)
 
 
 		if self.cfg.contract_data:
 		if self.cfg.contract_data:
 			m = "'--contract-data' option may not be used with token transaction"
 			m = "'--contract-data' option may not be used with token transaction"
@@ -82,12 +79,12 @@ class New(Base, TxBase.New):
 
 
 	def set_gas_with_data(self, data):
 	def set_gas_with_data(self, data):
 		if not self.is_token:
 		if not self.is_token:
-			self.gas = self.proto.coin_amt(self.dfl_gas + self.byte_cost * len(data), from_unit='wei')
+			self.gas = self.dfl_gas + self.byte_cost * len(data)
 
 
 	# one-shot method
 	# one-shot method
 	def adj_gas_with_extra_data_len(self, extra_data_len):
 	def adj_gas_with_extra_data_len(self, extra_data_len):
 		if not (self.is_token or hasattr(self, '_gas_adjusted')):
 		if not (self.is_token or hasattr(self, '_gas_adjusted')):
-			self.gas += self.proto.coin_amt(self.byte_cost * extra_data_len, from_unit='wei')
+			self.gas += self.byte_cost * extra_data_len
 			self._gas_adjusted = True
 			self._gas_adjusted = True
 
 
 	async def process_cmdline_args(self, cmd_args, ad_f, ad_w):
 	async def process_cmdline_args(self, cmd_args, ad_f, ad_w):
@@ -154,7 +151,7 @@ class New(Base, TxBase.New):
 
 
 	# given rel fee and units, return absolute fee using self.gas
 	# given rel fee and units, return absolute fee using self.gas
 	def fee_rel2abs(self, tx_size, amt_in_units, unit):
 	def fee_rel2abs(self, tx_size, amt_in_units, unit):
-		return self.proto.coin_amt(int(amt_in_units * self.gas.toWei()), from_unit=unit)
+		return self.proto.coin_amt(int(amt_in_units * self.gas), from_unit=unit)
 
 
 	# given fee estimate (gas price) in wei, return absolute fee, adjusting by self.cfg.fee_adjust
 	# given fee estimate (gas price) in wei, return absolute fee, adjusting by self.cfg.fee_adjust
 	def fee_est2abs(self, net_fee):
 	def fee_est2abs(self, net_fee):

+ 1 - 1
mmgen/proto/eth/tx/signed.py

@@ -35,7 +35,7 @@ class Signed(Completed, TxBase.Signed):
 			'to':       CoinAddr(self.proto, d['to']) if d['to'] else None,
 			'to':       CoinAddr(self.proto, d['to']) if d['to'] else None,
 			'amt':      self.proto.coin_amt(d['value'], from_unit='wei'),
 			'amt':      self.proto.coin_amt(d['value'], from_unit='wei'),
 			'gasPrice': self.proto.coin_amt(d['gasprice'], from_unit='wei'),
 			'gasPrice': self.proto.coin_amt(d['gasprice'], from_unit='wei'),
-			'startGas': self.proto.coin_amt(d['startgas'], from_unit='wei'),
+			'startGas': d['startgas'],
 			'nonce':    ETHNonce(d['nonce']),
 			'nonce':    ETHNonce(d['nonce']),
 			'data':     HexStr(d['data']) }
 			'data':     HexStr(d['data']) }
 		if o['data'] and not o['to']: # token- or contract-creating transaction
 		if o['data'] and not o['to']: # token- or contract-creating transaction

+ 5 - 3
mmgen/proto/eth/tx/unsigned.py

@@ -32,7 +32,9 @@ class Unsigned(Completed, TxBase.Unsigned):
 			'to':       CoinAddr(self.proto, d['to']) if d['to'] else None,
 			'to':       CoinAddr(self.proto, d['to']) if d['to'] else None,
 			'amt':      self.proto.coin_amt(d['amt']),
 			'amt':      self.proto.coin_amt(d['amt']),
 			'gasPrice': self.proto.coin_amt(d['gasPrice']),
 			'gasPrice': self.proto.coin_amt(d['gasPrice']),
-			'startGas': self.proto.coin_amt(d['startGas']),
+			'startGas': (
+				self.proto.coin_amt(d['startGas']).toWei() if '.' in d['startGas'] # for backward compat
+				else int(d['startGas'])),
 			'nonce':    ETHNonce(d['nonce']),
 			'nonce':    ETHNonce(d['nonce']),
 			'chainId':  None if d['chainId'] == 'None' else Int(d['chainId']),
 			'chainId':  None if d['chainId'] == 'None' else Int(d['chainId']),
 			'data':     HexStr(d['data'])}
 			'data':     HexStr(d['data'])}
@@ -43,7 +45,7 @@ class Unsigned(Completed, TxBase.Unsigned):
 	async def do_sign(self, o, wif):
 	async def do_sign(self, o, wif):
 		o_conv = {
 		o_conv = {
 			'to':       bytes.fromhex(o['to'] or ''),
 			'to':       bytes.fromhex(o['to'] or ''),
-			'startgas': o['startGas'].toWei(),
+			'startgas': o['startGas'],
 			'gasprice': o['gasPrice'].toWei(),
 			'gasprice': o['gasPrice'].toWei(),
 			'value':    o['amt'].toWei() if o['amt'] else 0,
 			'value':    o['amt'].toWei() if o['amt'] else 0,
 			'nonce':    o['nonce'],
 			'nonce':    o['nonce'],
@@ -129,7 +131,7 @@ class TokenUnsigned(TokenCompleted, Unsigned):
 				self.swap_memo.encode(),
 				self.swap_memo.encode(),
 				o['expiry'])
 				o['expiry'])
 			tx_in = c.make_tx_in(
 			tx_in = c.make_tx_in(
-				gas = self.gas * (7.8 if self.cfg.test_suite else 2),
+				gas = self.gas * (7 if self.cfg.test_suite else 2),
 				gasPrice = o['gasPrice'],
 				gasPrice = o['gasPrice'],
 				nonce = o['nonce'] + 1,
 				nonce = o['nonce'] + 1,
 				data = cdata)
 				data = cdata)

+ 1 - 1
test/cmdtest_d/ethdev.py

@@ -340,7 +340,7 @@ class CmdTestEthdevMethods:
 					to_addr   = usr_addrs[i],
 					to_addr   = usr_addrs[i],
 					amt       = amt,
 					amt       = amt,
 					key       = dfl_devkey,
 					key       = dfl_devkey,
-					gas       = self.proto.coin_amt(120000, from_unit='wei'),
+					gas       = 120000,
 					gasPrice  = self.proto.coin_amt(8, from_unit='Gwei'))
 					gasPrice  = self.proto.coin_amt(8, from_unit='Gwei'))
 				rpc = await self.rpc
 				rpc = await self.rpc
 				for n in range(50): # long delay for txbump
 				for n in range(50): # long delay for txbump

+ 34 - 12
test/cmdtest_d/ethswap.py

@@ -83,14 +83,15 @@ class CmdTestEthSwapMethods:
 	def token_fund_user(self):
 	def token_fund_user(self):
 		return self._token_transfer_ops(
 		return self._token_transfer_ops(
 			op          = 'fund_user',
 			op          = 'fund_user',
-			mm_idxs     = [1],
+			mm_idxs     = [1, 2, 12],
+			token_addr  = 'token_addr1',
 			amt         = self.token_fund_amt)
 			amt         = self.token_fund_amt)
 
 
 	def token_addrgen(self):
 	def token_addrgen(self):
-		return self._token_addrgen(mm_idxs=[1], naddrs=5)
+		return self._token_addrgen(mm_idxs=[1], naddrs=12)
 
 
 	def token_addrimport(self):
 	def token_addrimport(self):
-		return self._token_addrimport('token_addr1', '1-5', expect='5/5')
+		return self._token_addrimport('token_addr1', '1-12', expect='12/12')
 
 
 	def token_addrimport_inbound(self):
 	def token_addrimport_inbound(self):
 		token_addr = self.read_from_tmpfile('token_addr1').strip()
 		token_addr = self.read_from_tmpfile('token_addr1').strip()
@@ -176,9 +177,10 @@ class CmdTestEthSwap(CmdTestSwapMethods, CmdTestRegtest):
 	),
 	),
 	'eth_fund': (
 	'eth_fund': (
 		'funding the ETH tracking wallet',
 		'funding the ETH tracking wallet',
-		('eth_fund_mmgen_addr1', ''),
-		('eth_fund_mmgen_addr2', ''),
-		('eth_bal1',             ''),
+		('eth_fund_mmgen_addr1',  ''),
+		('eth_fund_mmgen_addr1b', ''),
+		('eth_fund_mmgen_addr2',  ''),
+		('eth_bal1',              ''),
 	),
 	),
 	'token_init': (
 	'token_init': (
 		'deploying tokens and initializing the ETH token tracking wallet',
 		'deploying tokens and initializing the ETH token tracking wallet',
@@ -227,7 +229,8 @@ class CmdTestEthSwap(CmdTestSwapMethods, CmdTestRegtest):
 	'eth_token_swap': (
 	'eth_token_swap': (
 		'swap operations (ETH -> ERC20, ERC20 -> BTC, ERC20 -> ETH)',
 		'swap operations (ETH -> ERC20, ERC20 -> BTC, ERC20 -> ETH)',
 		# ETH -> MM1
 		# ETH -> MM1
-		('eth_swaptxcreate3',          ''),
+		('eth_swaptxcreate3a',         ''),
+		('eth_swaptxcreate3b',         ''),
 		('eth_swaptxsign3',            ''),
 		('eth_swaptxsign3',            ''),
 		('eth_swaptxsend3',            ''),
 		('eth_swaptxsend3',            ''),
 		('eth_swaptxmemo3',            ''),
 		('eth_swaptxmemo3',            ''),
@@ -240,7 +243,8 @@ class CmdTestEthSwap(CmdTestSwapMethods, CmdTestRegtest):
 		('eth_swaptxreceipt4',         ''),
 		('eth_swaptxreceipt4',         ''),
 		('eth_token_bal2',             ''),
 		('eth_token_bal2',             ''),
 		# MM1 -> ETH
 		# MM1 -> ETH
-		('eth_swaptxcreate5',          ''),
+		('eth_swaptxcreate5a',         ''),
+		('eth_swaptxcreate5b',         ''),
 		('eth_swaptxsign5',            ''),
 		('eth_swaptxsign5',            ''),
 		('eth_etherscan_server_start', ''),
 		('eth_etherscan_server_start', ''),
 		('eth_swaptxsend5_test',       ''),
 		('eth_swaptxsend5_test',       ''),
@@ -343,6 +347,7 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 	cmd_group_in = CmdTestEthdev.cmd_group_in + (
 	cmd_group_in = CmdTestEthdev.cmd_group_in + (
 		# eth_fund:
 		# eth_fund:
 		('fund_mmgen_addr1',         'funding user address :1)'),
 		('fund_mmgen_addr1',         'funding user address :1)'),
+		('fund_mmgen_addr1b',        'funding user address :3)'),
 		('fund_mmgen_addr2',         'funding user address :11)'),
 		('fund_mmgen_addr2',         'funding user address :11)'),
 		('bal1',                     'the ETH balance'),
 		('bal1',                     'the ETH balance'),
 		# eth_swap:
 		# eth_swap:
@@ -367,7 +372,8 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 
 
 		# eth_token_swap:
 		# eth_token_swap:
 		# ETH -> MM1
 		# ETH -> MM1
-		('swaptxcreate3',          'creating an ETH->MM1 swap transaction'),
+		('swaptxcreate3a',         'creating an ETH->MM1 swap transaction'),
+		('swaptxcreate3b',         'creating an ETH->MM1 swap transaction (specific address)'),
 		('swaptxsign3',            'signing the transaction'),
 		('swaptxsign3',            'signing the transaction'),
 		('swaptxsend3',            'sending the transaction'),
 		('swaptxsend3',            'sending the transaction'),
 		('swaptxmemo3',            'the memo of the sent transaction'),
 		('swaptxmemo3',            'the memo of the sent transaction'),
@@ -382,7 +388,8 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 		('token_bal2',             'the token balance'),
 		('token_bal2',             'the token balance'),
 
 
 		# MM1 -> ETH
 		# MM1 -> ETH
-		('swaptxcreate5',          'creating an MM1->ETH swap transaction'),
+		('swaptxcreate5a',         'creating an MM1->ETH swap transaction'),
+		('swaptxcreate5b',         'creating an MM1->ETH swap transaction (specific address)'),
 		('swaptxsign5',            'signing the transaction'),
 		('swaptxsign5',            'signing the transaction'),
 		('etherscan_server_start', 'starting the Etherscan server'),
 		('etherscan_server_start', 'starting the Etherscan server'),
 		('swaptxsend5_test',       'testing the transaction via Etherscan'),
 		('swaptxsend5_test',       'testing the transaction via Etherscan'),
@@ -392,6 +399,9 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 		('etherscan_server_stop',  'stopping the Etherscan server'),
 		('etherscan_server_stop',  'stopping the Etherscan server'),
 	)
 	)
 
 
+	def fund_mmgen_addr1b(self):
+		return self._fund_mmgen_addr(arg=f'{dfl_sid}:E:3,0.001')
+
 	def swaptxcreate1(self):
 	def swaptxcreate1(self):
 		t = self._swaptxcreate(['ETH', '8.765', 'BTC'])
 		t = self._swaptxcreate(['ETH', '8.765', 'BTC'])
 		t.expect('OK? (Y/n): ', 'y')
 		t.expect('OK? (Y/n): ', 'y')
@@ -404,7 +414,13 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 				add_opts = ['--trade-limit=3%']),
 				add_opts = ['--trade-limit=3%']),
 			expect = ':2019e4/1/0')
 			expect = ':2019e4/1/0')
 
 
-	def swaptxcreate3(self):
+	def swaptxcreate3a(self):
+		t = self._swaptxcreate(['ETH', '0.7654321', 'ETH.MM1'])
+		t.expect(f'{dfl_sid}:E:4') # check that correct unused address was found
+		t.expect('(Y/n): ', 'y')
+		return self._swaptxcreate_ui_common(t)
+
+	def swaptxcreate3b(self):
 		t = self._swaptxcreate(['ETH', '8.765', 'ETH.MM1', f'{dfl_sid}:E:5'])
 		t = self._swaptxcreate(['ETH', '8.765', 'ETH.MM1', f'{dfl_sid}:E:5'])
 		return self._swaptxcreate_ui_common(t)
 		return self._swaptxcreate_ui_common(t)
 
 
@@ -424,7 +440,13 @@ class CmdTestEthSwapEth(CmdTestEthSwapMethods, CmdTestSwapMethods, CmdTestEthdev
 		t = self._swaptxcreate(['ETH.MM1', '87.654321', 'BTC', f'{dfl_sid}:C:2'])
 		t = self._swaptxcreate(['ETH.MM1', '87.654321', 'BTC', f'{dfl_sid}:C:2'])
 		return self._swaptxcreate_ui_common(t)
 		return self._swaptxcreate_ui_common(t)
 
 
-	def swaptxcreate5(self):
+	def swaptxcreate5a(self):
+		t = self._swaptxcreate(['ETH.MM1', '98.7654321', 'ETH'])
+		t.expect(f'{dfl_sid}:E:13') # check that correct unused address was found
+		t.expect('(Y/n): ', 'y')
+		return self._swaptxcreate_ui_common(t)
+
+	def swaptxcreate5b(self):
 		t = self._swaptxcreate(['ETH.MM1', '98.7654321', 'ETH', f'{dfl_sid}:E:12'])
 		t = self._swaptxcreate(['ETH.MM1', '98.7654321', 'ETH', f'{dfl_sid}:E:12'])
 		return self._swaptxcreate_ui_common(t)
 		return self._swaptxcreate_ui_common(t)