def __eq__(self, other): if type(other) is str: try: address = web3.toChecksumAddress(other) return address == self.address except ValueError: return False return super().__eq__(other)
def at(self, address): '''Retrieves an Account instance from the address string. Raises ValueError if the account cannot be found. Args: address: string of the account address. Returns: Account instance. ''' try: address = web3.toChecksumAddress(address) except ValueError: raise ValueError("{} is not a valid address".format(address)) try: return next(i for i in self._accounts if i == address) except StopIteration: raise ValueError("No account exists for {}".format(address))
def at(self, address, owner=None, tx=None): '''Returns a contract address. Raises ValueError if no bytecode exists at the address. Args: address: Address string of the contract. owner: Default Account instance to send contract transactions from. tx: Transaction ID of the contract creation.''' address = web3.toChecksumAddress(address) if address in deployed_contracts[self._name]: return deployed_contracts[self._name][address] contract = find_contract(address) if contract: raise ValueError("Contract '{}' already declared at {}".format( contract._name, address)) if web3.eth.getCode(address).hex() == "0x": raise ValueError("No contract deployed at {}".format(address)) contract = Contract(address, self._build, owner, tx) deployed_contracts[self._name][address] = contract if CONFIG['active_network']['persist']: add_contract(self._name, address, tx.hash if tx else None, owner) return deployed_contracts[self._name][address]
def _get_trace(self): '''Retrieves the stack trace via debug_traceTransaction, and adds the following attributes to each step: address: The address executing this contract. contractName: The name of the contract. fn: The name of the function. source: Start and end offset associated source code. jumpDepth: Number of jumps made since entering this contract. The initial value is 1.''' self.trace = [] self.return_value = None self.revert_msg = None if (self.input == "0x" and self.gas_used == 21000) or self.contract_address: return trace = web3.providers[0].make_request('debug_traceTransaction', [self.txid, {}]) if 'error' in trace: raise ValueError(trace['error']['message']) self.trace = trace = trace['result']['structLogs'] c = contract.find_contract(self.receiver or self.contract_address) last = { 0: { 'address': self.receiver or self.contract_address, 'contract': c._name, 'fn': [self.fn_name.split('.')[-1]], } } pc = c._build['pcMap'][0] trace[0].update({ 'address': last[0]['address'], 'contractName': last[0]['contract'], 'fn': last[0]['fn'][-1], 'jumpDepth': 1, 'source': { 'filename': pc['contract'], 'start': pc['start'], 'stop': pc['stop'] } }) for i in range(1, len(trace)): # if depth has increased, tx has called into a different contract if trace[i]['depth'] > trace[i - 1]['depth']: address = web3.toChecksumAddress(trace[i - 1]['stack'][-2][-40:]) c = contract.find_contract(address) stack_idx = -4 if trace[i - 1]['op'] in ('CALL', 'CALLCODE') else -3 memory_idx = int(trace[i - 1]['stack'][stack_idx], 16) * 2 sig = "0x" + "".join( trace[i - 1]['memory'])[memory_idx:memory_idx + 8] last[trace[i]['depth']] = { 'address': address, 'contract': c._name, 'fn': [next(k for k, v in c.signatures.items() if v == sig)], } trace[i].update({ 'address': last[trace[i]['depth']]['address'], 'contractName': last[trace[i]['depth']]['contract'], 'fn': last[trace[i]['depth']]['fn'][-1], 'jumpDepth': len(set(last[trace[i]['depth']]['fn'])) }) c = contract.find_contract(trace[i]['address']) pc = c._build['pcMap'][trace[i]['pc']] trace[i]['source'] = { 'filename': pc['contract'], 'start': pc['start'], 'stop': pc['stop'] } # jump 'i' is moving into an internal function if pc['jump'] == 'i': source = c._build['source'][pc['start']:pc['stop']] if source[:7] not in ("library", "contrac") and "(" in source: fn = source[:source.index('(')].split('.')[-1] else: fn = last[trace[i]['depth']]['fn'][-1] last[trace[i]['depth']]['fn'].append(fn) # jump 'o' is coming out of an internal function elif pc['jump'] == "o" and len(last[trace[i]['depth']]['fn']) > 1: last[trace[i]['depth']]['fn'].pop()
def find_contract(address): address = web3.toChecksumAddress(address) contracts = [x for v in deployed_contracts.values() for x in v.values()] return next((i for i in contracts if i == address), False)
def __contains__(self, address): try: address = web3.toChecksumAddress(address) return address in self._accounts except ValueError: return False