From fb07b089beab7f4a56db1bfb68599c27f7fb45e2 Mon Sep 17 00:00:00 2001 From: MMGen Date: Wed, 6 Feb 2019 11:05:37 +0000 Subject: [PATCH] py3port: ERC20: support/require Solidity compiler version 0.5.3 --- scripts/create-token.py | 67 ++++++++++++++++++++++++----------------- test/test.py | 24 ++++++++------- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/scripts/create-token.py b/scripts/create-token.py index a4e085e4..5fbf4acd 100755 --- a/scripts/create-token.py +++ b/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 . -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[] = _totalSupply; emit Transfer(address(0), , _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) diff --git a/test/test.py b/test/test.py index 9529e065..84b015d4 100755 --- a/test/test.py +++ b/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))