def test_echidna_instrumentation(self): self.inorder_config.instrumentation.predicates = [ 'previously(b_called) -> c_called', 'b_called -> since(c_called, a_called)' ] self.inorder_config.instrumentation.for_echidna = True self.inorder_config.verification.verisol.use = False proof_found, verisol_counterexample = self.inorder_veriman.analyze_contract( self.inorder_config, reuse_pre_process=True) # Restore test configs: self.inorder_config.instrumentation.for_echidna = False self.inorder_config.verification.verisol.use = True self.check_contract_compiles(self.inorder_veriman.contract_path) slither = Slither(self.inorder_veriman.contract_path) contract_info = slither.get_contract_from_name('InOrder') echidna_invariants = list( filter(lambda func: func.name.startswith('echidna_'), contract_info.functions)) self.assertEqual(len(echidna_invariants), 2) for invariant in echidna_invariants: self.assertEqual(invariant.return_type[0].name, 'bool') self.check_functions_with_asserts(self.inorder_veriman, []) os.remove(self.inorder_veriman.contract_path)
def test_inheritance(self): inheritance_config = TestVeriMan.get_test_config() inheritance_config.contract.path = os.path.dirname( os.path.abspath(__file__)) + '/Inheritance.sol' inheritance_config.contract.name = 'D' inheritance_config.instrumentation.predicates = [ 'a_var + b_var + c_var + d_var < 10', 'block.number > 10' ] inheritance_config.verification.verisol.use = False veriman = VeriMan() proof_found, verisol_counterexample = veriman.analyze_contract( inheritance_config) self.check_contract_compiles(veriman.contract_path) slither = Slither(veriman.contract_path) contract_info = slither.get_contract_from_name( inheritance_config.contract.name) expected_functions = set( list([ 'aFunction', 'toBeOverwritten', 'bFunction', 'withTheSameName', 'callsC', 'dFunction', 'constructor' ])) found_functions = list( map(lambda func: func.name, contract_info.functions_declared)) self.assertEqual(found_functions.count('withTheSameName'), 3) self.assertEqual(found_functions.count('toBeOverwritten'), 1) self.assertEqual(expected_functions, set(found_functions)) os.remove(veriman.contract_path)
def run(filename, contract_name): """Executes script""" # Init Slither slither = Slither(filename) # Get an instance of the contract to be analyzed contract = slither.get_contract_from_name(contract_name) if not contract: print(f"Contract {contract_name} not found") print( "Either you mispelled the contract's name or solc cannot compile the contract." ) exit(-1) # Obtain all visible functions, filtering out any that comes from an interface contract visible_functions = get_visible_functions( get_implemented_functions(contract.functions)) erc20_fx_matches = verify_signatures(visible_functions, ERC20_FX_SIGNATURES) print("== ERC20 functions definition ==") log_matches(erc20_fx_matches) print("\n== Custom modifiers ==") log_modifiers_per_function(verify_custom_modifiers(erc20_fx_matches)) print("\n== ERC20 events ==") log_matches(verify_signatures(contract.events, ERC20_EVENT_SIGNATURES), log_return=False) log_event_per_function( verify_event_calls(erc20_fx_matches, ERC20_EVENT_BY_FX), ERC20_EVENT_BY_FX) print("\n== ERC20 getters ==") log_matches( verify_getters(contract.state_variables, visible_functions, ERC20_GETTERS)) print("\n== Allowance frontrunning mitigation ==") frontrun_fx_matches = verify_signatures(visible_functions, ALLOWANCE_FRONTRUN_FX_SIGNATURES) log_matches(frontrun_fx_matches) log_event_per_function(verify_event_calls(frontrun_fx_matches, ALLOWANCE_FRONTRUN_EVENT_BY_FX), ALLOWANCE_FRONTRUN_EVENT_BY_FX, must=False) print("\n== Balance check in approve function ==") approve_signature = ERC20_FX_SIGNATURES[1].to_string(with_return=False, with_spaces=False) approve_function = contract.get_function_from_signature(approve_signature) is_checking_balance = any( checks_sender_balance_in_require(node) for node in approve_function.nodes) log_approve_checking_balance(is_checking_balance)
def pre_process_contract(self, contract_path, contract_name): self.contract_path = contract_path self.contract_name = contract_name slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name) if self.contract_info is None: raise Exception('Check config file for contract name') with open(self.contract_path) as contract_file: self.contract_lines = contract_file.readlines() self.__add_constructor(slither) self.__add_inherited_functions() # TODO improve efficiency: with open(self.contract_path, 'w') as contract_file: contract_file.writelines(self.contract_lines) slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name)
def instrument(self, contract_path, contract_name, predicates, instrument_for_echidna): self.contract_path = contract_path self.contract_name = contract_name slither = Slither(self.contract_path) self.contract_info = slither.get_contract_from_name(self.contract_name) if self.contract_info is None: raise Exception('Check config file for contract name') with open(self.contract_path) as contract_file: contract = contract_file.read() contract = contract.replace('}', '\n}') self.contract_lines = contract.split('\n') self.__pre_process_contract() parser = Parser() echidna_function = '' for index, predicate_string in enumerate(predicates): predicate = parser.parse(predicate_string) functions_to_instrument = self.__get_functions_to_instrument( predicate) self.__instrument_new_variables(predicate, functions_to_instrument, instrument_for_echidna) if instrument_for_echidna: echidna_function += '(' + predicate.solidity_repr + ')\n&& ' else: assert_string = f'assert({predicate.solidity_repr}); // VERIMAN ASSERT FOR PREDICATE NO. {index + 1}' self.__insert_in_functions(functions_to_instrument, assert_string, self.__insert_at_end_of_functions) if instrument_for_echidna: echidna_function = 'function echidna_invariant() public returns(bool) {\nreturn ' \ + echidna_function.rsplit('\n&& ', 1)[0]\ + ';\n}' self.__insert_in_contract(echidna_function) contract = '\n'.join(self.contract_lines) with open(self.contract_path, 'w') as contract_file: contract_file.write(contract)
def check_functions_with_asserts(self, veriman, expected): slither = Slither(veriman.contract_path) contract_info = slither.get_contract_from_name(veriman.contract_name) expected_functions = set(list(expected)) found_functions = list( filter( lambda func: next( filter(lambda call: call.name == 'assert(bool)', func. solidity_calls), None) is not None, contract_info.functions_declared)) found_functions_names = list( map(lambda func: func.name, found_functions)) self.assertEqual(expected_functions, set(found_functions_names))
def instantiate_dsl(sol_file, analysis, lambdas): ## Step 1: parse the original source .sol. # Init slither slither = Slither(sol_file) # Get the contract, all the contact's name is C by default. contract = slither.get_contract_from_name('C') other_contracts = list( filter(lambda x: x != 'C', map(str, slither.contracts))) harness_fun = contract.functions[0] vars_map = {} # Get the function, which has name 'foo' by default. assert harness_fun.name == 'foo' for var in harness_fun.variables_read: add_var(vars_map, var) for var in harness_fun.variables_written: add_var(vars_map, var) actual_spec = toy_spec_str int_str = "" address_str = "" maparray_str = "" mapint_str = "" prog_decl = "" with open(sol_file, "r") as f: ind = "//#LOOPVARS: " body = f.read() if ind in body: global_vars = body[body.index(ind) + 12:].split("\n")[0] global_vars = global_vars.replace('[', "").replace( ']', "").replace("'", "").replace(" ", "").split(", ") else: global_vars = ["i"] #TODO: HANDLE NESTED LOOPS i_global = global_vars[0] in list(map(str, contract.variables)) for k in vars_map: for v in vars_map[k]: if v == global_vars[0]: if i_global: prog_decl += k + ' ' + v + '; \n' else: prog_decl += k + ' ' + v + '; \n' # TODO: Presumes all constants are integers or booleans for const in analysis[5]: try: if 'uint256' in vars_map: vars_map['uint256'].append(str(int(const))) else: vars_map['uint256'] = [str(int(const))] except: if 'bool' in vars_map: vars_map['bool'].append(const) else: vars_map['bool'] = [const] base_types = ["uint", "bool", "address", "bytes"] + other_contracts map_types = list( map(lambda x: "mapping({0} => {1})".format(x[0], x[1]), product(base_types, repeat=2))) all_types = base_types + map_types type_table = {} length_vars = [] for k in vars_map: v = map(lambda x: '"' + x + '"', vars_map[k]) actual_symbols = ",".join(list(v)) print('parsing key:', k, ",".join(list(v))) if "[]" in k: length_vars += vars_map[k] k = "mapping(uint => {0})".format(k.replace("[]", "")) k = k.replace("uint8", "uint") k = k.replace("uint128", "uint") k = k.replace("uint256", "uint") k = k.replace("bytes32", "bytes") if k in all_types: if k in map_types: matches = re.findall(r"(mapping\((.*) => (.*)\))", k) if matches != []: full_dec = matches[0][0] dom = matches[0][1] codom = matches[0][2] k = "mapping_{0}_{1}".format(dom, codom) if not k in type_table: type_table[k] = actual_symbols.split(",") else: type_table[k] += actual_symbols.split(",") else: print("IGNORED TYPE: {0}!".format(k)) pass if "uint" in type_table: type_table["uint"] += list( map(lambda v: '"{0}.length"'.format(v), length_vars)) else: type_table["uint"] = list( map(lambda v: '"{0}.length"'.format(v), length_vars)) typ_enums, final_typ_dict = create_refinement_types( analysis, type_table, lambdas) actual_spec = expand_dsl(actual_spec, final_typ_dict, base_types) actual_spec = actual_spec.format(types=typ_enums) # print(actual_spec) return actual_spec, prog_decl, final_typ_dict, i_global, global_vars
import sys from slither.slither import Slither if len(sys.argv) != 2: print('python.py function_called.py functions_called.sol') exit(-1) # Init slither slither = Slither(sys.argv[1]) # Get the contract contract = slither.get_contract_from_name('Contract') # Get the variable entry_point = contract.get_function_from_signature('entry_point()') all_calls = entry_point.all_internal_calls() all_calls_formated = [f.contract.name + '.' + f.name for f in all_calls] # Print the result print( 'From entry_point the functions reached are {}'.format(all_calls_formated))
import sys from slither.slither import Slither if len(sys.argv) != 2: print("python function_writing.py functions_writing.sol") sys.exit(-1) # Init slither slither = Slither(sys.argv[1]) # Get the contract contracts = slither.get_contract_from_name("Contract") assert len(contracts) == 1 contract = contracts[0] # Get the variable var_a = contract.get_state_variable_from_name("a") # Get the functions writing the variable functions_writing_a = contract.get_functions_writing_to_variable(var_a) # Print the result print('The function writing "a" are {}'.format( [f.name for f in functions_writing_a]))
import sys from slither.slither import Slither from slither.slithir.convert import convert_expression if len(sys.argv) != 4: print( 'python.py function_called.py functions_called.sol Contract function()' ) exit(-1) # Init slither slither = Slither(sys.argv[1]) # Get the contract contract = slither.get_contract_from_name(sys.argv[2]) # Get the variable test = contract.get_function_from_signature(sys.argv[3]) #test = contract.get_function_from_signature('two()') nodes = test.nodes for node in nodes: if node.expression: print('Expression:\n\t{}'.format(node.expression)) irs = convert_expression(node.expression) print('IR expressions:') for ir in irs: print('\t{}'.format(ir)) print()
import sys from slither.slither import Slither from slither.slithir.convert import convert_expression if len(sys.argv) != 2: print('python function_called.py functions_called.sol') exit(-1) # Init slither slither = Slither(sys.argv[1]) # Get the contract contract = slither.get_contract_from_name('Test') # Get the variable test = contract.get_function_from_signature('one()') nodes = test.nodes for node in nodes: if node.expression: print('Expression:\n\t{}'.format(node.expression)) irs = convert_expression(node.expression) print('IR expressions:') for ir in irs: print('\t{}'.format(ir)) print()
from slither.slither import Slither slither = Slither('coin.sol') coin = slither.get_contract_from_name('Coin')[0] # Iterate over all the contracts for contract in slither.contracts: # If the contract is derived from MyContract if coin in contract.inheritance: # Get the function definition mint = contract.get_function_from_signature('_mint(address,uint256)') # If the function was not declarer by coin, there is a bug ! if mint.contract != coin: print(f'Error, {contract} overrides {mint}')
import sys from slither.slither import Slither from slither.slithir.convert import convert_expression if len(sys.argv) != 2: print("python function_called.py functions_called.sol") sys.exit(-1) # Init slither slither = Slither(sys.argv[1]) # Get the contract contracts = slither.get_contract_from_name("Test") assert len(contracts) == 1 contract = contracts[0] # Get the variable test = contract.get_function_from_signature("one()") assert test nodes = test.nodes for node in nodes: if node.expression: print(f"Expression:\n\t{node.expression}") irs = convert_expression(node.expression, node) print("IR expressions:") for ir in irs: print(f"\t{ir}") print()