Browse Source

py3port: ERC20: support/require Solidity compiler version 0.5.3

MMGen 6 years ago
parent
commit
fb07b089be
2 changed files with 52 additions and 39 deletions
  1. 39 28
      scripts/create-token.py
  2. 13 11
      test/test.py

+ 39 - 28
scripts/create-token.py

@@ -16,7 +16,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-import sys,os,json
+import sys,os,json,re
 from subprocess import Popen,PIPE
 from mmgen.common import *
 from mmgen.obj import CoinAddr,is_coin_addr
@@ -25,6 +25,7 @@ decimals = 18
 supply   = 10**26
 name   = 'MMGen Token'
 symbol = 'MMT'
+solc_version = '0.5.3'
 
 opts_data = lambda: {
 	'desc': 'Create an ERC20 token contract',
@@ -37,21 +38,24 @@ opts_data = lambda: {
 -t, --supply=  t Total supply of the token (default: {t})
 -s, --symbol=  s Token symbol (default: {s})
 -S, --stdout     Output data in JSON format to stdout instead of files
+-v, --verbose    Produce more verbose output
 """.format(d=decimals,n=name,s=symbol,t=supply)
 }
 
 cmd_args = opts.init(opts_data)
 assert g.coin in ('ETH','ETC'),'--coin option must be set to ETH or ETC'
 
-if not len(cmd_args) == 1 or not is_coin_addr(cmd_args[0]):
+if not len(cmd_args) == 1 or not is_coin_addr(cmd_args[0].lower()):
 	opts.usage()
 
-owner_addr = '0x' + CoinAddr(cmd_args[0])
+owner_addr = '0x' + cmd_args[0]
 
 # ERC Token Standard #20 Interface
 # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
+
 code_in = """
-pragma solidity ^0.4.18;
+
+pragma solidity >0.5.2 <0.5.4;
 
 contract SafeMath {
     function safeAdd(uint a, uint b) public pure returns (uint c) {
@@ -73,9 +77,9 @@ contract SafeMath {
 }
 
 contract ERC20Interface {
-    function totalSupply() public constant returns (uint);
-    function balanceOf(address tokenOwner) public constant returns (uint balance);
-    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
+    function totalSupply() public returns (uint);
+    function balanceOf(address tokenOwner) public returns (uint balance);
+    function allowance(address tokenOwner, address spender) public returns (uint remaining);
     function transfer(address to, uint tokens) public returns (bool success);
     function approve(address spender, uint tokens) public returns (bool success);
     function transferFrom(address from, address to, uint tokens) public returns (bool success);
@@ -84,11 +88,6 @@ contract ERC20Interface {
     event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
 }
 
-// Contract function to receive approval and execute function in one call
-contract ApproveAndCallFallBack {
-    function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
-}
-
 contract Owned {
     address public owner;
     address public newOwner;
@@ -136,10 +135,10 @@ contract Token is ERC20Interface, Owned, SafeMath {
         balances[<OWNER_ADDR>] = _totalSupply;
         emit Transfer(address(0), <OWNER_ADDR>, _totalSupply);
     }
-    function totalSupply() public constant returns (uint) {
+    function totalSupply() public returns (uint) {
         return _totalSupply  - balances[address(0)];
     }
-    function balanceOf(address tokenOwner) public constant returns (uint balance) {
+    function balanceOf(address tokenOwner) public returns (uint balance) {
         return balances[tokenOwner];
     }
     function transfer(address to, uint tokens) public returns (bool success) {
@@ -160,19 +159,9 @@ contract Token is ERC20Interface, Owned, SafeMath {
         emit Transfer(from, to, tokens);
         return true;
     }
-    function allowance(address tokenOwner, address spender) public constant returns (uint remaining) {
+    function allowance(address tokenOwner, address spender) public returns (uint remaining) {
         return allowed[tokenOwner][spender];
     }
-    function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
-        allowed[msg.sender][spender] = tokens;
-        emit Approval(msg.sender, spender, tokens);
-        ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
-        return true;
-    }
-    // Don't accept ETH
-    function () public payable {
-        revert();
-    }
     // Owner can transfer out any accidentally sent ERC20 tokens
     function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
         return ERC20Interface(tokenAddress).transfer(owner, tokens);
@@ -181,20 +170,42 @@ contract Token is ERC20Interface, Owned, SafeMath {
 """
 
 def create_src(code):
-	for k in ('decimals','supply','name','symbol','owner_addr'):
+	for k in ('decimals','supply','name','symbol','owner_addr','solc_version'):
 		if hasattr(opt,k) and getattr(opt,k): globals()[k] = getattr(opt,k)
 		code = code.replace('<{}>'.format(k.upper()),str(globals()[k]))
 	return code
 
+def check_version():
+	p = Popen(['solc','--version'],stdout=PIPE)
+	res = p.stdout.read().decode()
+	ver = re.search(r'Version:\s*(.*)',res).group(1)
+	msg("Installed solc version: {}".format(ver))
+	if not re.search(r'{}\b'.format(solc_version),ver):
+		ydie(1,'Incorrect Solidity compiler version (need version {})'.format(solc_version))
+
 def compile_code(code):
+	check_version()
 	cmd = ['solc','--optimize','--bin','--overwrite']
 	if not opt.stdout: cmd += ['--output-dir', opt.outdir or '.']
+	cmd += ['-']
+	msg('Executing: {}'.format(' '.join(cmd)))
 	p = Popen(cmd,stdin=PIPE,stdout=PIPE,stderr=PIPE)
 	res = p.communicate(code.encode())
-	o = res[0].decode().replace('\r','').split('\n')
-	dmsg(res[1])
+	out = res[0].decode().replace('\r','')
+	err = res[1].decode().replace('\r','').strip()
+	rc = p.wait()
+	if rc != 0:
+		rmsg('Solidity compiler produced the following error:')
+		msg(err)
+		rdie(2,'Solidity compiler exited with error (return val: {})'.format(rc))
+	if err:
+		ymsg('Solidity compiler produced the following warning:')
+		msg(err)
 	if opt.stdout:
+		o = out.split('\n')
 		return dict((k,o[i+2]) for k in ('SafeMath','Owned','Token') for i in range(len(o)) if k in o[i])
+	else:
+		vmsg(out)
 
 src = create_src(code_in)
 out = compile_code(src)

+ 13 - 11
test/test.py

@@ -133,6 +133,7 @@ opts_data = lambda: {
 --, --longhelp       Print help message for long options (common options)
 -B, --bech32         Generate and use Bech32 addresses
 -b, --buf-keypress   Use buffered keypresses as with real human input
+                     (often required on slow systems, or under emulation)
 -c, --print-cmdline  Print the command line of each spawned command
 -C, --coverage       Produce code coverage info using trace module
 -x, --debug-pexpect  Produce debugging output for pexpect calls
@@ -635,6 +636,7 @@ dfl_words = os.path.join(ref_dir,cfgs['8']['seed_id']+'.mmwords')
 
 # The Parity dev address with lots of coins.  Create with "ethkey -b info ''":
 eth_addr = '00a329c0648769a73afac7f9381e08fb43dbea72'
+eth_addr_chk = '00a329c0648769A73afAc7F9381E08FB43dBEA72'
 eth_key = '4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7'
 eth_burn_addr = 'deadbeef'*5
 eth_amt1 = '999999.12345689012345678'
@@ -655,31 +657,31 @@ eth_bals = {
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt1)],
 	'8': [  ('98831F3A:E:1','0'),
 			('98831F3A:E:2','23.45495'),
-			('98831F3A:E:11','1.2288376','a'),
+			('98831F3A:E:11','1.2288487','a'),
 			('98831F3A:E:12','99.99895'),
 			('98831F3A:E:21','2.345'),
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt1)],
 	'9': [  ('98831F3A:E:1','0'),
 			('98831F3A:E:2','23.45495'),
-			('98831F3A:E:11','1.2288376','a'),
-			('98831F3A:E:12','99.997087072'),
+			('98831F3A:E:11','1.2288487','a'),
+			('98831F3A:E:12','99.997092733'),
 			('98831F3A:E:21','2.345'),
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt1)]
 }
 eth_token_bals = {
 	'1': [  ('98831F3A:E:11','1000','1.234')],
-	'2': [  ('98831F3A:E:11','998.76544','1.2314236','a'),
+	'2': [  ('98831F3A:E:11','998.76544','1.23142915','a'),
 			('98831F3A:E:12','1.23456','0')],
-	'3': [  ('98831F3A:E:11','110.654317776666555545','1.2288376','a'),
+	'3': [  ('98831F3A:E:11','110.654317776666555545','1.2288487','a'),
 			('98831F3A:E:12','1.23456','0')],
-	'4': [  ('98831F3A:E:11','110.654317776666555545','1.2288376','a'),
+	'4': [  ('98831F3A:E:11','110.654317776666555545','1.2288487','a'),
 			('98831F3A:E:12','1.23456','0'),
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt2,eth_amt1)],
-	'5': [  ('98831F3A:E:11','110.654317776666555545','1.2288376','a'),
+	'5': [  ('98831F3A:E:11','110.654317776666555545','1.2288487','a'),
 			('98831F3A:E:12','1.23456','99.99895'),
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt2,eth_amt1)],
-	'6': [  ('98831F3A:E:11','110.654317776666555545','1.2288376','a'),
-			('98831F3A:E:12','0','99.997087072'),
+	'6': [  ('98831F3A:E:11','110.654317776666555545','1.2288487','a'),
+			('98831F3A:E:12','0','99.997092733'),
 			('98831F3A:E:13','1.23456','0'),
 			(eth_burn_addr + '\s+Non-MMGen',eth_amt2,eth_amt1)]
 }
@@ -3523,7 +3525,7 @@ class MMGenTestSuite(object):
 		MMGenExpect(name,'',msg_only=True)
 		cmd_args = ['--{}={}'.format(k,v) for k,v in list(token_data.items())]
 		imsg("Compiling solidity token contract '{}' with 'solc'".format(token_data['symbol']))
-		cmd = ['scripts/create-token.py','--coin='+g.coin,'--outdir='+cfg['tmpdir']] + cmd_args + [eth_addr]
+		cmd = ['scripts/create-token.py','--coin='+g.coin,'--outdir='+cfg['tmpdir']] + cmd_args + [eth_addr_chk]
 		imsg("Executing: {}".format(' '.join(cmd)))
 		subprocess.check_output(cmd,stderr=subprocess.STDOUT)
 		imsg("ERC20 token '{}' compiled".format(token_data['symbol']))
@@ -3685,7 +3687,7 @@ class MMGenTestSuite(object):
 		t.ok()
 
 	def ethdev_bal1_getbalance(self,name,t_non_mmgen='',t_mmgen=''):
-		ebal = Decimal('127.0287876')
+		ebal = Decimal('127.0287987')
 		if g.coin == 'ETC': ebal += self.bal_corr
 		self.ethdev_bal_getbalance(name,t_non_mmgen='999999.12345689012345678',t_mmgen=str(ebal))