def test_deploy_eth_contract(self): log = logging.getLogger("SidechainEthTest") with mock_server(SidechainEth) as stub: filename = 'test/HelloWorld.sol' with open(filename, 'r') as myfile: contract_source = myfile.read() contract_metadata = parser.parse_file(filename) contract_name = contract_metadata['children'][1]['name'] jwt_info = { 'network': self.network, 'eth_account_address': self.ela_eth_to_use, 'eth_private_key': '0x35a12175385b24b2f906d6027d440aac7bd31e1097311fa8e3cf21ceac7c4809', 'eth_gas': 2000000, 'contract_source': contract_source, 'contract_name': contract_name, } jwt_token = jwt.encode({ 'jwt_info': jwt_info, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=settings.TOKEN_EXPIRATION) }, self.api_key_to_use, algorithm='HS256') response = stub.DeployEthContract(sidechain_eth_pb2.Request(input=jwt_token), timeout=settings.REQUEST_TIMEOUT, metadata=[('did', self.did_to_use)]) log.debug(f"Method: test_deploy_eth_contract, Expected: True, Actual: {response.status}") self.assertEqual(response.status, True)
def run(): from solidity_parser import symbolic, parser asttree = parser.parse_file("BookStore.sol") f = open("renderToPython.py", 'w') f.write(open('init.py').read()) f.close() f = open("renderToPython.py", 'a+') dse = symbolic.SymbolicExecution(asttree,f ) listFunc= dse.run() f.close() import renderToPython transaction = renderToPython.BookStore() init = ('0xAAAA', (renderToPython.ownerToBalance['0xAAAA'], renderToPython.getSumToken(renderToPython.totalToken)), '0xBBBB', (renderToPython.ownerToBalance['0xBBBB']+renderToPython.msg.value, renderToPython.getSumToken(renderToPython.ownerToOrderList['0xBBBB']) )) transaction.implementTransaction('0xBBBB', 'mathematic', 1 ) final = ('0xAAAA',(renderToPython.ownerToBalance['0xAAAA'], renderToPython.getSumToken(renderToPython.totalToken)), '0xBBBB',(renderToPython.ownerToBalance['0xBBBB'], renderToPython.getSumToken(renderToPython.ownerToOrderList['0xBBBB']) )) return init, final
def parse_file(filepath: Path) -> dict: """ Parse a file using solidity_parser :param filepath: (:code:`str` or :class:`pathlib.Path`) Path to the source file to check :returns: (:code:`dict`) A Python dict representation of the source file """ return parser.parse_file(str(filepath))
def check_solidity_version(url): """Check if a repository is a fix repository by checking if it contains atleast one file with version >=0.4.19 :param url: URL of repository :return: True if repository is a fix repo else False """ # clone repo path = os.getcwd() + '/data' if not os.path.exists(path): os.mkdir('data') # check if repo has .sol files or not response = make_request(url + '/search?q=extension%3Asol', HEADER) parsed = BeautifulSoup(response.content, 'html.parser') try: parsed.find('div', class_='code-list').find('a')['href'] except Exception as e: logging.exception(e) logging.info('Does not contains .sol files') return False, '0' if not clone_repo(url, path): return False, '0' sol_files = get_sol_files(path + '/' + url.split('/')[-1]) for sol_file in sol_files: try: parsed = parser.parse_file(sol_file) ver = None for child in parsed['children']: if child['type'] == 'PragmaDirective': ver = child['value'] break # ver = parsed['children'][0]['value'].replace('^','') if not ver: logging.error('File version not found in file ' + str(sol_file)) continue ver = ver.replace('^', '') if '<' in ver: ver = ver.split('<')[0] file_sol_ver = semantic_version.SimpleSpec(ver) # checking if version >= 0.4.19 req_sol_ver = semantic_version.SimpleSpec('>=0.4.19') if req_sol_ver.match(file_sol_ver.clause.target): shutil.rmtree(path + '/' + url.split('/')[-1]) return True, len(sol_files) except Exception as e: logging.exception(e) continue # delete cloned copy of repo shutil.rmtree(path + '/' + url.split('/')[-1]) return False, '0'
def runSC(admin, user_address, ownerToOrderList, ownerToBalance, totalToken, book_isbn, book_quantity, book_price): # cần build msg from solidity_parser import symbolic, parser import collections asttree = parser.parse_file("BookStore.sol") f = open("renderToPython.py", 'w') f.write(open('init.py').read()) f_write(f, 'admin', admin, 'str') f_write(f, 'user_address', user_address, 'str') f_write(f, 'totalToken', totalToken, 'dict') f.write("ownerToOrderList = collections.defaultdict(lambda : 0)\n") f_write(f, "ownerToOrderList[user_address]", ownerToOrderList[user_address], 'dict') f.write( "ownerToOrderList[user_address]=convert(ownerToOrderList[user_address])\n" ) f.write("ownerToBalance= collections.defaultdict(lambda : 0)\n") f_write(f, "ownerToBalance[admin]", ownerToBalance[admin], 'number') f_write(f, "ownerToBalance[user_address]", ownerToBalance[user_address], 'number') f_write(f, "ownerToBalance['0xcAd4954fA4cb431bAD9a84c3ae8e279fe069A6De']", ownerToBalance['0xcAd4954fA4cb431bAD9a84c3ae8e279fe069A6De'], 'number') f_write(f, "book_quantity", book_quantity, 'number') f_write(f, "book_price", book_price, 'number') f_write(f, "book_isbn", book_isbn, 'str') f.write("msg = Msg(admin, user_address, book_price*book_quantity)\n") f.write("ownerToBalance['0x0000'] = msg.value\n") f.close() f = open("renderToPython.py", 'a+') dse = symbolic.SymbolicExecution(asttree, f) listFunc = dse.run() f.close() import renderToPython transaction = renderToPython.BookStore() init = ( renderToPython.admin, (renderToPython.ownerToBalance[renderToPython.admin], renderToPython.getSumToken(renderToPython.totalToken)), renderToPython.user_address, (renderToPython.ownerToBalance[renderToPython.user_address] + renderToPython.msg.value, renderToPython.getSumToken( renderToPython.ownerToOrderList[renderToPython.user_address]))) transaction.implementTransaction(user_address, book_isbn, book_quantity) final = ( renderToPython.admin, (renderToPython.ownerToBalance[renderToPython.admin], renderToPython.getSumToken(renderToPython.totalToken)), renderToPython.user_address, (renderToPython.ownerToBalance[renderToPython.user_address], renderToPython.getSumToken( renderToPython.ownerToOrderList[renderToPython.user_address]))) return init, final
def convert_to_ast(self): """ Break down Solidity Contract into an AST object. """ try: self.source_unit = parser.parse_file(self.file_path) # Subparse AST into objects for nicer interfaces: Create a nested # object structure from AST self.source_unit_object = parser.objectify(self.source_unit) except AttributeError: self.status = 'invalid'
def deploy_eth_contract(self, api_key, did, network, eth_account_address, eth_private_key, eth_gas, filename): with open(filename, 'r') as myfile: contract_source = myfile.read() contract_metadata = parser.parse_file(filename) contract_name = contract_metadata['children'][1]['name'] jwt_info = { 'network': network, 'eth_account_address': eth_account_address, 'eth_private_key': eth_private_key, 'eth_gas': eth_gas, 'contract_source': contract_source, 'contract_name': contract_name, } jwt_token = jwt.encode( { 'jwt_info': jwt_info, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=TOKEN_EXPIRATION) }, api_key, algorithm='HS256') response = self.stub.DeployEthContract( sidechain_eth_pb2.Request(input=jwt_token), timeout=REQUEST_TIMEOUT, metadata=[('did', did)]) if response.status: output = jwt.decode(response.output, key=api_key, algorithms=['HS256']).get('jwt_info') result = { 'output': json.dumps(output), 'status_message': response.status_message, 'status': response.status } return result else: result = { 'output': '', 'status_message': response.status_message, 'status': response.status } return result
import sys import pprint from solidity_parser import parser sourceUnit = parser.parse_file(sys.argv[1]) #pprint.pprint(sourceUnit) sourceUnitObject = parser.objectify(sourceUnit) # access imports, contracts, functions, ... (see outline example in # __main__.py) sourceUnitObject.imports # [] sourceUnitObject.pragmas # [] for contract_name in sourceUnitObject.contracts.keys(): print(contract_name)
def create_log_contract(input_filename, output_filename): sourceUnit = parser.parse_file(input_filename) pragma = "" for child in sourceUnit["children"]: # Get the pragma version # It should always be the first line near the top before the contract definitions if child["type"] == "PragmaDirective": pragma = "pragma solidity " + child['value'] + ";\n" elif child["type"] == "ContractDefinition": subnodes = child['subNodes'] statevariables = dict() contractName = child['name'] + "Log" for node in subnodes: nodetype = node['type'] # Get all the state variables # If it is an address, make note of it it is payable if nodetype == 'StateVariableDeclaration': for variable in node['variables']: if variable['visibility'] == 'public': # At the moment, this framework will only work on state variables that are of type : ElementaryTypeName if variable['typeName']['type'] == "ElementaryTypeName": statevariables[variable['name']] = variable["typeName"]["name"] # Write the log contract f = open(output_filename, "w") f.write(pragma) f.write("contract " + contractName + " {\n") for variable in statevariables: variabletype = statevariables[variable] f.write("\t" + variabletype + " public " + variable + ";\n") constructor = "constructor (" idx = 0 for variable in statevariables: if idx > 0: constructor += "," variabletype = statevariables[variable] if variabletype == "string": constructor += variabletype + " memory _" + variable else: constructor += variabletype + " _" + variable idx += 1 constructor += ") public {\n" for pair in sorted(statevariables.items()): variable = pair[0] constructor += variable + " = _" + variable + ";\n" constructor += "}\n" f.write(constructor) # Fallback function # f.write("function () public payable {}\n") for variable in statevariables: variabletype = statevariables[variable] function = "function update" + variable + " (" if variabletype == "string": function += variabletype + " memory _" + variable else: function += variabletype + " _" + variable function += ") public {\n" function += "\t" + variable + " = _" + variable + ";\n" function += "}\n" f.write(function) f.write("}") f.close()
def apply_CDTF(input_filename, output_filename, logfilename): sourceUnit = parser.parse_file(input_filename) f = open(input_filename, "r") contract = f.read() f.close() operator_signs = ["+", "-", "*", "/"] for child in sourceUnit["children"]: if child["type"] == "ContractDefinition": subnodes = child['subNodes'] statevariables = dict() contractName = child['name'] contractLogTypeName = contractName + "Log" contractLogVariableName = contractLogTypeName + "logs" functions_to_modify = [] cdtf_enter_re = r"@CDTF\s+ENTER\s*function.+\(.*\).*{" cdtf_end_re = r"@CDTF\s+END\s*function.+\(.*\).*{" for node in subnodes: nodetype = node['type'] # Get all the state variables # If it is an address, make note of it it is payable if nodetype == 'StateVariableDeclaration': for variable in node['variables']: if variable['visibility'] == 'public': # At the moment, this framework will only work on state variables that are of type : ElementaryTypeName if variable['typeName']['type'] == "ElementaryTypeName": statevariables[variable['name']] = variable["typeName"]["name"] elif nodetype == "FunctionDefinition" and not node['isConstructor']: name = node['name'] definition_re = r"@CDTF\s*function\s+" + name + r"\s*\(.*\).*{" functionDefinitionresult = re.search(definition_re, contract) if functionDefinitionresult is None: # Check for the ENTER tag definition_re = r"@CDTF\s+ENTER\s*function\s+" + name + r"\s*\(.*\).*{" functionDefinitionresult = re.search(definition_re, contract) if functionDefinitionresult is None: definition_re = r"@CDTF\s+END\s*function\s+" + name + r"\s*\(.*\).*{" functionDefinitionresult = re.search(definition_re, contract) if functionDefinitionresult is None: continue else: cdtf_end_re = definition_re else: cdtf_enter_re = definition_re functions_to_modify.append(definition_re) if len(logfilename) < 2 or logfilename[:2] != "./": logfilename = "./" + logfilename import_statement = "import \"" + logfilename + "\";" # Create the instance variable logs_var = contractLogTypeName + " private " + contractLogVariableName + ";" # Insert this at the very start of the contract contractdefinition = r"contract\s+" + contractName + r".*{" contractdefinitionResult = re.search(contractdefinition, contract).group() # Add the contract log contract = re.sub(contractdefinitionResult, import_statement + "\n" + contractdefinitionResult + "\n" + logs_var + "\n", contract) cdtf_enter = re.search(cdtf_enter_re, contract) cdtf_end = re.search(cdtf_end_re, contract) if cdtf_enter is None or cdtf_end is None: # There is no cdtf entrance continue # For every place that contains @CDTF tag, replce all variable assignemnts and reads to Log updates and reads for func_def in functions_to_modify: # First, replace all +=, -=, /=, and *= new_func_def = find_function(contract, func_def) original_function = new_func_def for var in statevariables: for sign in operator_signs: var_re = var + r"\s*[" + sign + r"]=" new_update_statement = var + " = " + var + " " + sign + " " new_func_def = re.sub(var_re, new_update_statement, new_func_def) # Next, replace all assignment statements with a call to the update function in the log for var in statevariables: var_assignment_re = var + r"\s*=" var_assignment_re_result = re.search(var_assignment_re, new_func_def) if var_assignment_re_result is not None: new_update_statement = contractLogVariableName + ".update" + var + "(" new_func_def = new_func_def.replace(var_assignment_re_result.group(), new_update_statement ) # Add the ending parenthesis var_update_re = r"(?<=" + contractLogVariableName + ".update" + var + r"\().*;" update_parameters = re.findall(var_update_re, new_func_def) for result in update_parameters: update_parameter_modified = new_update_statement + result[:-1] + ");" new_func_def = new_func_def.replace(new_update_statement + result, update_parameter_modified) # Finally, replace all remaining uses of the state variable to calls to the log function for var in statevariables: log_read_statement = contractLogVariableName + "." + var + "() " variable_re = r"[^0-9A-Fa-f]" + var + r"[^0-9A-Fa-f]" variable_results = re.findall(variable_re, new_func_def) for result in variable_results: newresult = result.replace(var, log_read_statement) new_func_def = new_func_def.replace(result, newresult) contract = contract.replace(original_function, new_func_def) # Find the @CDTF ENTER tag. That indicates where to create the log contract contract_creation = contractLogVariableName + " = new " + contractLogTypeName + "(" first = True for var in statevariables: if not first: contract_creation += "," else: first = False contract_creation += var contract_creation += ");" contract = re.sub(cdtf_enter_re, cdtf_enter.group() + "\n" + contract_creation + "\n", contract) # Find the @CDTF END tag. This indicates at the end, you need to update the contract contract_update = "" for var in statevariables: contract_update += var + " = " + contractLogVariableName + "." + var + "();\n" ending_function = find_function(contract, cdtf_end_re) new_ending_function = ending_function[:-1] + "\n" + contract_update + "\n}" contract = contract.replace(ending_function, new_ending_function) # Write the new contract into a file f = open(output_filename, "w") f.write(contract) f.close
def parse_contract(self): self.parsed_contract = parser.parse_file(self.contract_path)
def main(): global currentcontractobject global spaces parsedtree = parser.parse_file("samplecontract.sol") # Contracts written in local file parsedtreeobject = parser.objectify(parsedtree) pprint.pprint(parsedtree) all_contracts_names = parsedtreeobject.contracts.keys() # get all contract names all_contracts_names = list(all_contracts_names) for contract_name in all_contracts_names: print(f"\n\n-------------------\tInformation of Contract: {contract_name}\t-------------------\n") currentcontractobject = parsedtreeobject.contracts[contract_name] state_variables_names = list(parsedtreeobject.contracts[contract_name].stateVars.keys()) print(f"All State Variables Are:\n{state_variables_names}") global metaarray metaarray = [] storage_index = 0 byte_index = 0 for variable_name in state_variables_names: print("Storage Index: " + str(storage_index)) varprops = [] print(f"\n\n{spaces}Properties of a Variable:\n\n{spaces}Name:\t\t\t{variable_name}") statevariableobject = parsedtreeobject.contracts[contract_name].stateVars[variable_name] varprops.append(statevariableobject['typeName']['type']) varprops.append(variable_name) if statevariableobject['typeName']['type'] == 'ElementaryTypeName': variable_type = statevariableobject['typeName']['name'] varprops.append(variable_type) storage_index, byte_index, v2 = elementaryvariables(statevariableobject, variable_type, storage_index, byte_index) varprops = varprops + v2 metaarray.append(varprops) continue if statevariableobject['typeName']['type'] == 'UserDefinedTypeName': # Check if struct if statevariableobject['typeName']['namePath'] in list( parsedtreeobject.contracts[contract_name].structs.keys()): variable_type = statevariableobject['typeName']['namePath'] varprops.append(variable_type) storage_index, byte_index, v2 = structs(statevariableobject, variable_type, storage_index, byte_index) varprops = varprops + v2 metaarray.append(varprops) continue if statevariableobject['typeName']['namePath'] in list( parsedtreeobject.contracts[contract_name].enums.keys()): variable_type = statevariableobject['typeName']['namePath'] varprops.append(variable_type) storage_index, byte_index, v2 = enums(statevariableobject, variable_type, storage_index, byte_index) varprops = varprops + v2 metaarray.append(varprops) continue if statevariableobject['typeName']['type'] == 'ArrayTypeName': storage_index, byte_index, v2 = arraytype(statevariableobject, storage_index, byte_index) varprops = varprops + v2 metaarray.append(varprops) continue if statevariableobject['typeName']['type'] == 'Mapping': variable_name = statevariableobject['name'] keytype = statevariableobject['typeName']['keyType']['name'] if statevariableobject['typeName']['valueType']['type'] == 'ElementaryTypeName': valuetype = statevariableobject['typeName']['valueType']['name'] else: valuetype = statevariableobject['typeName']['valueType']['namePath'] st = str(keytype) + "=>" + str(valuetype) varprops.append(st) if byte_index != 0: storage_index += 1 byte_index = 0 print(f"{spaces}Key Type:\t\t{keytype}\n\tValue Type:\t\t" f"{valuetype}\n\tIndex Assigned:\t{storage_index}") varprops.append(storage_index) varprops.append(None) varprops.append(32) storage_index += 1 metaarray.append(varprops) continue print(f"{spaces}The State Variable given is of Unhandled Type. Type:" f" {statevariableobject['typeName']['type']}") break print("\n\n==================================================================\nGeneral:\tVariable Type | Name | " "Data " "Type | Storage Index | Byte Index | Size\nArrays:\t\tVariable Type | Name | Data " "Type | [ 1st Packed Patch: [Storage Index | Byte Index | Size], ...]\n\n") for row in metaarray: print(row)
def apply_SDTF(input_filename, output_filename): # This script will append on additional parameters to each SDTF marked function. # The variable names will equal {variable_prefix}_{state variable name} # The new parameters will be added to the front of the parameter list and in alphabetical order # Only function definitions that are immediately proceded by the tag @STDF in a comment will be considered sourceUnit = parser.parse_file(input_filename) f = open(input_filename, "r") contract = f.read() f.close() variable_prefix = "readset" for child in sourceUnit["children"]: # If there is more than one contract definition within this file, then this script # assumes that every function between the two contracts has a different name if child["type"] == "ContractDefinition": subnodes = child['subNodes'] statevariables = dict() # Iterate once through to grab all the statevariables for node in subnodes: nodetype = node['type'] if nodetype == 'StateVariableDeclaration': for variable in node['variables']: if variable['visibility'] == 'public': # At the moment, this framework will only work on state variables that are of type : ElementaryTypeName if variable['typeName'][ 'type'] == "ElementaryTypeName": statevariables[variable['name']] = variable[ "typeName"]["name"] # Iterate again to examine each function definition for node in subnodes: nodetype = node['type'] if nodetype == "FunctionDefinition" and not node[ 'isConstructor']: # Identify all the statevariables that are used in each function body = node['body'] name = node['name'] used_state_variables = list( extract_state_variables(body, statevariables.keys())) used_state_variables.sort() if len(used_state_variables) > 0: # First, get the list of parameters definition_re = r"@SDTF\s*function\s+" + name + r"\(" functiondefinitionResult = re.search( definition_re, contract) if functiondefinitionResult is None: continue functiondefinition = functiondefinitionResult.group() # Create the require statement and updated parameter list requires = "require(" for idx, variable in enumerate(used_state_variables): if idx > 0: requires += " && " functiondefinition += "," requires += variable + " == " + variable_prefix + "_" + variable functiondefinition += statevariables[ variable] + " " + variable_prefix + "_" + variable requires += ", \"Readset of contract data at time of calling is stale\");" # Append parameters to this function. # Also check if there are any parameters in this function already. If so, then you will need to append a comma to the end of the new functiondefinition if len(node['parameters']['parameters']) > 0: functiondefinition += "," # Add the requires statement old_definition = re.search( r"function\s+" + name + r"\(.*\).*\{", contract).group() contract = re.sub( r"function\s+" + name + r"\(.*\).*\{", old_definition + "\n" + requires + "\n", contract) # Update the parameter list contract = re.sub(definition_re, functiondefinition, contract) # Write the new contract into a file f = open(output_filename, "w") f.write(contract) f.close
cwd = os.getcwd() os.system( f"cd {repo} && node ./node_modules/.bin/prettier --write {target} --config .prettierrc && cd {cwd}" ) arg_parser = argparse.ArgumentParser( description= "Generates Solidity rich reverts library and corresponding Typescript classes from boilerplate." ) arg_parser.add_argument("--repo", help="Absolute path to monorepo.") arg_parser.add_argument( "--lib_path", help= "Path (relative to monorepo) to Solidity file containing library boilerplate.", ) args = arg_parser.parse_args() sol_target = f"{args.repo}/{args.lib_path}" ts_target = get_ts_target(args.repo, args.lib_path) sourceUnit = parser.parse_file(sol_target) sourceUnitObject = parser.objectify(sourceUnit) contractName = list(sourceUnitObject.contracts.keys())[0] contractObject = sourceUnitObject.contracts[contractName] sol_codegen(contractName, contractObject, sol_target) ts_codegen(contractObject, args.repo, ts_target)