123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- #!/usr/bin/env python3
- #
- # mmgen = Multi-Mode GENerator, command-line Bitcoin cold storage solution
- # Copyright (C)2013-2019 The MMGen Project <mmgen@tuta.io>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # 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,re
- from subprocess import Popen,PIPE
- from mmgen.common import *
- from mmgen.obj import CoinAddr,is_coin_addr
- decimals = 18
- supply = 10**26
- name = 'MMGen Token'
- symbol = 'MMT'
- solc_version_pat = r'0.5.[123]'
- opts_data = {
- 'text': {
- 'desc': 'Create an ERC20 token contract',
- 'usage':'[opts] <owner address>',
- 'options': """
- -h, --help Print this help message
- -o, --outdir= d Specify output directory for *.bin files
- -d, --decimals=d Number of decimals for the token (default: {d})
- -n, --name=n Token name (default: {n})
- -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
- """
- },
- 'code': {
- 'options': lambda s: s.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].lower()):
- opts.usage()
- 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.5.0 <0.5.4;
- contract SafeMath {
- function safeAdd(uint a, uint b) public pure returns (uint c) {
- c = a + b;
- require(c >= a);
- }
- function safeSub(uint a, uint b) public pure returns (uint c) {
- require(b <= a);
- c = a - b;
- }
- function safeMul(uint a, uint b) public pure returns (uint c) {
- c = a * b;
- require(a == 0 || c / a == b);
- }
- function safeDiv(uint a, uint b) public pure returns (uint c) {
- require(b > 0);
- c = a / b;
- }
- }
- contract ERC20Interface {
- 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);
- event Transfer(address indexed from, address indexed to, uint tokens);
- event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
- }
- contract Owned {
- address public owner;
- address public newOwner;
- event OwnershipTransferred(address indexed _from, address indexed _to);
- constructor() public {
- owner = msg.sender;
- }
- modifier onlyOwner {
- require(msg.sender == owner);
- _;
- }
- function transferOwnership(address _newOwner) public onlyOwner {
- newOwner = _newOwner;
- }
- function acceptOwnership() public {
- require(msg.sender == newOwner);
- emit OwnershipTransferred(owner, newOwner);
- owner = newOwner;
- newOwner = address(0);
- }
- }
- // ----------------------------------------------------------------------------
- // ERC20 Token, with the addition of symbol, name and decimals and assisted
- // token transfers
- // ----------------------------------------------------------------------------
- contract Token is ERC20Interface, Owned, SafeMath {
- string public symbol;
- string public name;
- uint8 public decimals;
- uint public _totalSupply;
- mapping(address => uint) balances;
- mapping(address => mapping(address => uint)) allowed;
- constructor() public {
- symbol = "<SYMBOL>";
- name = "<NAME>";
- decimals = <DECIMALS>;
- _totalSupply = <SUPPLY>;
- balances[<OWNER_ADDR>] = _totalSupply;
- emit Transfer(address(0), <OWNER_ADDR>, _totalSupply);
- }
- function totalSupply() public returns (uint) {
- return _totalSupply - balances[address(0)];
- }
- function balanceOf(address tokenOwner) public returns (uint balance) {
- return balances[tokenOwner];
- }
- function transfer(address to, uint tokens) public returns (bool success) {
- balances[msg.sender] = safeSub(balances[msg.sender], tokens);
- balances[to] = safeAdd(balances[to], tokens);
- emit Transfer(msg.sender, to, tokens);
- return true;
- }
- function approve(address spender, uint tokens) public returns (bool success) {
- allowed[msg.sender][spender] = tokens;
- emit Approval(msg.sender, spender, tokens);
- return true;
- }
- function transferFrom(address from, address to, uint tokens) public returns (bool success) {
- balances[from] = safeSub(balances[from], tokens);
- allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
- balances[to] = safeAdd(balances[to], tokens);
- emit Transfer(from, to, tokens);
- return true;
- }
- function allowance(address tokenOwner, address spender) public returns (uint remaining) {
- return allowed[tokenOwner][spender];
- }
- // 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);
- }
- }
- """
- def create_src(code):
- for k in ('decimals','supply','name','symbol','owner_addr'):
- 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_pat),ver):
- ydie(1,'Incorrect Solidity compiler version (need version {})'.format(solc_version_pat))
- 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())
- 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 {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)
- if opt.stdout:
- print(json.dumps(out))
- msg('Contract successfully compiled')
|