Browse Source

scripts/create-token.py: cleanups, sanity checks

The MMGen Project 3 years ago
parent
commit
530571f610
1 changed files with 47 additions and 30 deletions
  1. 47 30
      scripts/create-token.py

+ 47 - 30
scripts/create-token.py

@@ -18,15 +18,17 @@
 
 import sys,os,json,re
 from subprocess import run,PIPE
+from collections import namedtuple
 from mmgen.common import *
 
+ti = namedtuple('token_param_info',['default','conversion','test'])
 class TokenData:
-	attrs = ('decimals','supply','name','symbol','owner_addr')
-	decimals = 18
-	supply = 10**26
-	name = 'MMGen Token'
-	symbol = 'MMT'
-	owner_addr = None
+	fields = ('decimals','supply','name','symbol','owner_addr')
+	decimals   = ti('18', int, lambda s: s.isdigit() and 0 < int(s) <= 36)
+	name       = ti(None, str, lambda s: s.isascii() and s.isprintable() and len(s) < 256)
+	supply     = ti(None, int, lambda s: s.isdigit() and 0 < int(s) <= 2**256 - 1)
+	symbol     = ti(None, str, lambda s: s.isascii() and s.isalnum() and len(s) <= 20)
+	owner_addr = ti(None, str, lambda s: s.isascii() and s.isalnum() and len(s) == 40) # checked separately
 
 token_data = TokenData()
 
@@ -39,10 +41,11 @@ opts_data = {
 		'options': f"""
 -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: {token_data.decimals})
--n, --name=N      Token name (default: {token_data.name!r})
--t, --supply=T    Total supply of the token (default: {token_data.supply})
--s, --symbol=S    Token symbol (default: {token_data.symbol!r})
+-d, --decimals=D  Number of decimals for the token (default: {token_data.decimals.default})
+-n, --name=N      Token name (REQUIRED)
+-p, --preprocess  Print the preprocessed code to stdout
+-t, --supply=T    Total supply of the token (REQUIRED)
+-s, --symbol=S    Token symbol (REQUIRED)
 -S, --stdout      Output JSON data to stdout instead of files
 -v, --verbose     Produce more verbose output
 -c, --check-solc-version Check the installed solc version
@@ -131,12 +134,12 @@ contract Token is ERC20Interface, Owned, SafeMath {
     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);
+        symbol = "$symbol";
+        name = "$name";
+        decimals = $decimals;
+        _totalSupply = $supply;
+        balances[$owner_addr] = _totalSupply;
+        emit Transfer(address(0), $owner_addr, _totalSupply);
     }
     function totalSupply() public override returns (uint) {
         return _totalSupply  - balances[address(0)];
@@ -172,13 +175,30 @@ contract Token is ERC20Interface, Owned, SafeMath {
 }
 """ % req_solc_ver_pat
 
-def create_src(code,token_data,owner_addr):
-	token_data.owner_addr = '0x' + owner_addr
-	for k in token_data.attrs:
-		if getattr(opt,k,None):
-			setattr( token_data, k, getattr(opt,k) )
-		code = code.replace( f'<{k.upper()}>', str(getattr(token_data,k)) )
-	return code
+def create_src(proto,template,token_data,owner_addr):
+
+	def gen():
+		for k in token_data.fields:
+			field = getattr(token_data,k)
+			val = (
+				owner_addr     if k == 'owner_addr' else
+				getattr(opt,k) if getattr(opt,k,None) else
+				field.default  if field.default is not None else
+				die(1,f'The --{k} option must be specified')
+			)
+
+			if k == 'owner_addr':
+				from mmgen.obj import is_coin_addr
+				if not is_coin_addr( proto, owner_addr.lower() ):
+					die(1,f'{owner_addr}: not a valid {proto.coin} coin address')
+				val = '0x' + val
+			elif not field.test(val):
+				die(1,f'{val!r}: invalid parameter for option --{k}')
+
+			yield(k,field.conversion(val))
+
+	from string import Template
+	return Template(template).substitute(**dict(gen()))
 
 def check_solc_version():
 	"""
@@ -250,15 +270,12 @@ if __name__ == '__main__':
 	if not len(cmd_args) == 1:
 		opts.usage()
 
-	owner_addr = cmd_args[0]
+	code = create_src( proto, solidity_code_template, token_data, cmd_args[0] )
 
-	from mmgen.obj import is_coin_addr
-	if not is_coin_addr( proto, owner_addr.lower() ):
-		die(1,f'{owner_addr}: not a valid {proto.coin} coin address')
+	if opt.preprocess:
+		Die(0,code)
 
-	out = compile_code(
-		create_src( solidity_code_template, token_data, owner_addr )
-	)
+	out = compile_code(code)
 
 	if opt.stdout:
 		print(json.dumps(out))