def deploy_dependencies_symbols(all_contract): dependencies = {} symbols_to_contract = dict() for contract_name in all_contract: symbol = solidity_library_symbol(contract_name) if symbol in symbols_to_contract: raise ValueError('Conflicting library names.') symbols_to_contract[symbol] = contract_name for contract_name, contract in all_contract.items(): unresolved_symbols = solidity_unresolved_symbols(contract['bin']) dependencies[contract_name] = [ symbols_to_contract[unresolved] for unresolved in unresolved_symbols ] return dependencies
def deploy_solidity_contract( self, # pylint: disable=too-many-locals contract_name, all_contracts, libraries, constructor_parameters, contract_path=None, timeout=None, ): """ Deploy a solidity contract. Args: sender (address): the sender address contract_name (str): the name of the contract to compile all_contracts (dict): the json dictionary containing the result of compiling a file libraries (list): A list of libraries to use in deployment constructor_parameters (tuple): A tuple of arguments to pass to the constructor contract_path (str): If we are dealing with solc >= v0.4.9 then the path to the contract is a required argument to extract the contract data from the `all_contracts` dict. timeout (int): Amount of time to poll the chain to confirm deployment """ if contract_name in all_contracts: contract_key = contract_name elif contract_path is not None: contract_key = os.path.basename( contract_path) + ':' + contract_name if contract_key not in all_contracts: raise ValueError('Unknown contract {}'.format(contract_name)) else: raise ValueError( 'Unknown contract {} and no contract_path given'.format( contract_name)) libraries = dict(libraries) contract = all_contracts[contract_key] contract_interface = contract['abi'] symbols = solidity_unresolved_symbols(contract['bin']) if symbols: available_symbols = list( map(solidity_library_symbol, all_contracts.keys())) unknown_symbols = set(symbols) - set(available_symbols) if unknown_symbols: msg = 'Cannot deploy contract, known symbols {}, unresolved symbols {}.'.format( available_symbols, unknown_symbols, ) raise Exception(msg) dependencies = deploy_dependencies_symbols(all_contracts) deployment_order = dependencies_order_of_build( contract_key, dependencies) deployment_order.pop() # remove `contract_name` from the list log.debug('Deploying dependencies: {}'.format( str(deployment_order))) for deploy_contract in deployment_order: dependency_contract = all_contracts[deploy_contract] hex_bytecode = solidity_resolve_symbols( dependency_contract['bin'], libraries) bytecode = unhexlify(hex_bytecode) dependency_contract['bin'] = bytecode transaction_hash_hex = self.send_transaction( to=Address(b''), data=bytecode, ) transaction_hash = unhexlify(transaction_hash_hex) self.poll(transaction_hash, timeout=timeout) receipt = self.web3.eth.getTransactionReceipt(transaction_hash) contract_address = receipt['contractAddress'] # remove the hexadecimal prefix 0x from the address contract_address = contract_address[2:] libraries[deploy_contract] = contract_address deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( 'Contract address has no code, check gas usage.') hex_bytecode = solidity_resolve_symbols(contract['bin'], libraries) bytecode = unhexlify(hex_bytecode) contract['bin'] = bytecode if isinstance(contract['bin'], str): contract['bin'] = unhexlify(contract['bin']) if not constructor_parameters: constructor_parameters = () contract = self.web3.eth.contract(abi=contract['abi'], bytecode=contract['bin']) bytecode = contract.constructor( *constructor_parameters).buildTransaction()['data'] transaction_hash_hex = self.send_transaction( to=Address(b''), data=bytecode, ) transaction_hash = unhexlify(transaction_hash_hex) self.poll(transaction_hash, timeout=timeout) receipt = self.web3.eth.getTransactionReceipt(transaction_hash) contract_address = receipt['contractAddress'] deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( 'Deployment of {} failed. Contract address has no code, check gas usage.' .format(contract_name, )) return self.new_contract_proxy( contract_interface, contract_address, )
def deploy_solidity_contract( self, # pylint: disable=too-many-locals contract_name: str, all_contracts: Dict[str, ABI], libraries: Dict[str, str] = None, constructor_parameters: Tuple[Any] = None, contract_path: str = None, ): """ Deploy a solidity contract. Args: contract_name: The name of the contract to compile. all_contracts: The json dictionary containing the result of compiling a file. libraries: A list of libraries to use in deployment. constructor_parameters: A tuple of arguments to pass to the constructor. contract_path: If we are dealing with solc >= v0.4.9 then the path to the contract is a required argument to extract the contract data from the `all_contracts` dict. """ if libraries: libraries = dict(libraries) else: libraries = dict() ctor_parameters = constructor_parameters or () all_contracts = copy.deepcopy(all_contracts) if contract_name in all_contracts: contract_key = contract_name elif contract_path is not None: contract_key = os.path.basename( contract_path) + ":" + contract_name if contract_key not in all_contracts: raise ValueError("Unknown contract {}".format(contract_name)) else: raise ValueError( "Unknown contract {} and no contract_path given".format( contract_name)) contract = all_contracts[contract_key] contract_interface = contract["abi"] symbols = solidity_unresolved_symbols(contract["bin"]) if symbols: available_symbols = list( map(solidity_library_symbol, all_contracts.keys())) unknown_symbols = set(symbols) - set(available_symbols) if unknown_symbols: msg = "Cannot deploy contract, known symbols {}, unresolved symbols {}.".format( available_symbols, unknown_symbols) raise Exception(msg) dependencies = deploy_dependencies_symbols(all_contracts) deployment_order = dependencies_order_of_build( contract_key, dependencies) deployment_order.pop() # remove `contract_name` from the list log.debug("Deploying dependencies: {}".format( str(deployment_order)), node=pex(self.address)) for deploy_contract in deployment_order: dependency_contract = all_contracts[deploy_contract] hex_bytecode = solidity_resolve_symbols( dependency_contract["bin"], libraries) bytecode = decode_hex(hex_bytecode) dependency_contract["bin"] = bytecode gas_limit = self.web3.eth.getBlock( "latest")["gasLimit"] * 8 // 10 transaction_hash = self.send_transaction(to=Address(b""), startgas=gas_limit, data=bytecode) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt["contractAddress"] # remove the hexadecimal prefix 0x from the address contract_address = remove_0x_prefix(contract_address) libraries[deploy_contract] = contract_address deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( "Contract address has no code, check gas usage.") hex_bytecode = solidity_resolve_symbols(contract["bin"], libraries) bytecode = decode_hex(hex_bytecode) contract["bin"] = bytecode if isinstance(contract["bin"], str): contract["bin"] = decode_hex(contract["bin"]) contract_object = self.web3.eth.contract(abi=contract["abi"], bytecode=contract["bin"]) contract_transaction = contract_object.constructor( *ctor_parameters).buildTransaction() transaction_hash = self.send_transaction( to=Address(b""), data=contract_transaction["data"], startgas=self._gas_estimate_correction( contract_transaction["gas"]), ) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt["contractAddress"] deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( "Deployment of {} failed. Contract address has no code, check gas usage." .format(contract_name)) return self.new_contract_proxy(contract_interface, contract_address), receipt
def deploy_solidity_contract( self, # pylint: disable=too-many-locals contract_name, all_contracts, libraries=None, constructor_parameters=None, contract_path=None, ): """ Deploy a solidity contract. Args: sender (address): the sender address contract_name (str): the name of the contract to compile all_contracts (dict): the json dictionary containing the result of compiling a file libraries (list): A list of libraries to use in deployment constructor_parameters (tuple): A tuple of arguments to pass to the constructor contract_path (str): If we are dealing with solc >= v0.4.9 then the path to the contract is a required argument to extract the contract data from the `all_contracts` dict. """ if libraries is None: libraries = dict() if constructor_parameters is None: constructor_parameters = [] all_contracts = copy.deepcopy(all_contracts) if contract_name in all_contracts: contract_key = contract_name elif contract_path is not None: contract_key = os.path.basename(contract_path) + ':' + contract_name if contract_key not in all_contracts: raise ValueError('Unknown contract {}'.format(contract_name)) else: raise ValueError( 'Unknown contract {} and no contract_path given'.format(contract_name), ) libraries = dict(libraries) contract = all_contracts[contract_key] contract_interface = contract['abi'] symbols = solidity_unresolved_symbols(contract['bin']) if symbols: available_symbols = list(map(solidity_library_symbol, all_contracts.keys())) unknown_symbols = set(symbols) - set(available_symbols) if unknown_symbols: msg = 'Cannot deploy contract, known symbols {}, unresolved symbols {}.'.format( available_symbols, unknown_symbols, ) raise Exception(msg) dependencies = deploy_dependencies_symbols(all_contracts) deployment_order = dependencies_order_of_build(contract_key, dependencies) deployment_order.pop() # remove `contract_name` from the list log.debug('Deploying dependencies: {}'.format(str(deployment_order))) for deploy_contract in deployment_order: dependency_contract = all_contracts[deploy_contract] hex_bytecode = solidity_resolve_symbols(dependency_contract['bin'], libraries) bytecode = unhexlify(hex_bytecode) dependency_contract['bin'] = bytecode transaction_hash_hex = self.send_transaction( to=Address(b''), data=bytecode, ) transaction_hash = unhexlify(transaction_hash_hex) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt['contractAddress'] # remove the hexadecimal prefix 0x from the address contract_address = contract_address[2:] libraries[deploy_contract] = contract_address deployed_code = self.web3.eth.getCode(to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError('Contract address has no code, check gas usage.') hex_bytecode = solidity_resolve_symbols(contract['bin'], libraries) bytecode = unhexlify(hex_bytecode) contract['bin'] = bytecode if isinstance(contract['bin'], str): contract['bin'] = unhexlify(contract['bin']) if not constructor_parameters: constructor_parameters = () contract = self.web3.eth.contract(abi=contract['abi'], bytecode=contract['bin']) bytecode = contract.constructor(*constructor_parameters).buildTransaction()['data'] transaction_hash_hex = self.send_transaction( to=Address(b''), data=bytecode, ) transaction_hash = unhexlify(transaction_hash_hex) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt['contractAddress'] deployed_code = self.web3.eth.getCode(to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( 'Deployment of {} failed. Contract address has no code, check gas usage.'.format( contract_name, ), ) return self.new_contract_proxy( contract_interface, contract_address, )