py3port: ERC20: support/require Solidity compiler version 0.5.3

This commit is contained in:
The MMGen Project 2019-02-06 11:05:37 +00:00
commit fb07b089be
2 changed files with 52 additions and 39 deletions

View file

@ -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)

View file

@ -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))