def get_proxy_contract(self, registry: BaseContractRegistry, target_address: str, proxy_name: str) -> VersionedContract: # Lookup proxies; Search for a registered proxy that targets this contract record records = registry.search(contract_name=proxy_name) dispatchers = list() for name, version, address, abi in records: proxy_contract = self.client.w3.eth.contract( abi=abi, address=address, version=version, ContractFactoryClass=self._CONTRACT_FACTORY) # Read this dispatchers target address from the blockchain proxy_live_target_address = proxy_contract.functions.target().call( ) if proxy_live_target_address == target_address: dispatchers.append(proxy_contract) if len(dispatchers) > 1: message = f"Multiple Dispatcher deployments are targeting {target_address}" raise self.InterfaceError(message) try: return dispatchers[0] except IndexError: raise self.UnknownContract( f"No registered Dispatcher deployments target {target_address}" )
def deploy_contract( self, deployer_address: str, registry: BaseContractRegistry, contract_name: str, *constructor_args, enroll: bool = True, gas_limit: int = None, confirmations: int = 0, contract_version: str = 'latest', **constructor_kwargs) -> Tuple[VersionedContract, TxReceipt]: """ Retrieve compiled interface data from the cache and return an instantiated deployed contract """ # # Build the deployment transaction # # deploy_transaction = dict() if gas_limit: deploy_transaction.update({'gas': gas_limit}) pprint_args = ', '.join( list(map(str, constructor_args)) + list(f"{k}={v}" for k, v in constructor_kwargs.items())) contract_factory = self.get_contract_factory( contract_name=contract_name, version=contract_version) self.log.info( f"Deploying contract {contract_name}:{contract_factory.version} with " f"deployer address {deployer_address} " f"and parameters {pprint_args}") constructor_function = contract_factory.constructor( *constructor_args, **constructor_kwargs) constructor_calldata = encode_constructor_arguments( self.client.w3, constructor_function, *constructor_args, **constructor_kwargs) if constructor_calldata: self.log.info(f"Constructor calldata: {constructor_calldata}") # # Transmit the deployment tx # # receipt = self.send_transaction(contract_function=constructor_function, sender_address=deployer_address, payload=deploy_transaction, confirmations=confirmations) # Success address = receipt['contractAddress'] self.log.info( f"Confirmed {contract_name}:{contract_factory.version} deployment: new address {address}" ) # # Instantiate & Enroll contract # contract = self.client.w3.eth.contract( address=address, abi=contract_factory.abi, version=contract_factory.version, ContractFactoryClass=self._CONTRACT_FACTORY) if enroll is True: registry.enroll(contract_name=contract_name, contract_address=contract.address, contract_abi=contract.abi, contract_version=contract.version) return contract, receipt # receipt
def get_contract_by_name( self, registry: BaseContractRegistry, contract_name: str, contract_version: str = None, enrollment_version: Union[int, str] = None, proxy_name: str = None, use_proxy_address: bool = True) -> VersionedContract: """ Instantiate a deployed contract from registry data, and assimilate it with its proxy if it is upgradeable. """ target_contract_records = registry.search( contract_name=contract_name, contract_version=contract_version) if not target_contract_records: raise self.UnknownContract( f"No such contract records with name {contract_name}:{contract_version}." ) if proxy_name: # Lookup proxies; Search for a published proxy that targets this contract record proxy_records = registry.search(contract_name=proxy_name) results = list() for proxy_name, proxy_version, proxy_address, proxy_abi in proxy_records: proxy_contract = self.client.w3.eth.contract( abi=proxy_abi, address=proxy_address, version=proxy_version, ContractFactoryClass=self._CONTRACT_FACTORY) # Read this dispatcher's target address from the blockchain proxy_live_target_address = proxy_contract.functions.target( ).call() for target_name, target_version, target_address, target_abi in target_contract_records: if target_address == proxy_live_target_address: if use_proxy_address: triplet = (proxy_address, target_version, target_abi) else: triplet = (target_address, target_version, target_abi) else: continue results.append(triplet) if len(results) > 1: address, _version, _abi = results[0] message = "Multiple {} deployments are targeting {}".format( proxy_name, address) raise self.InterfaceError(message.format(contract_name)) else: try: selected_address, selected_version, selected_abi = results[ 0] except IndexError: raise self.UnknownContract( f"There are no Dispatcher records targeting '{contract_name}':{contract_version}" ) else: # TODO: use_proxy_address doesnt' work in this case. Should we raise if used? # NOTE: 0 must be allowed as a valid version number if len(target_contract_records) != 1: if enrollment_version is None: m = f"{len(target_contract_records)} records enrolled " \ f"for contract {contract_name}:{contract_version} " \ f"and no version index was supplied." raise self.InterfaceError(m) enrollment_version = self.__get_enrollment_version_index( name=contract_name, contract_version=contract_version, version_index=enrollment_version, enrollments=len(target_contract_records)) else: enrollment_version = -1 # default _contract_name, selected_version, selected_address, selected_abi = target_contract_records[ enrollment_version] # Create the contract from selected sources unified_contract = self.client.w3.eth.contract( abi=selected_abi, address=selected_address, version=selected_version, ContractFactoryClass=self._CONTRACT_FACTORY) return unified_contract
def deploy_contract( self, deployer_address: str, registry: BaseContractRegistry, contract_name: str, *constructor_args, enroll: bool = True, gas_limit: int = None, contract_version: str = 'latest', **constructor_kwargs) -> Tuple[VersionedContract, dict]: """ Retrieve compiled interface data from the cache and return an instantiated deployed contract """ if not is_checksum_address(deployer_address): raise ValueError( f"{deployer_address} is not a valid EIP-55 checksum address.") # # Build the deployment transaction # # deploy_transaction = dict() if gas_limit: deploy_transaction.update({'gas': gas_limit}) pprint_args = str(tuple(constructor_args)) pprint_args = pprint_args.replace("{", "{{").replace("}", "}}") # See #724 contract_factory = self.get_contract_factory( contract_name=contract_name, version=contract_version) self.log.info( f"Deploying contract {contract_name}:{contract_factory.version} with " f"deployer address {deployer_address} " f"and parameters {pprint_args}") transaction_function = contract_factory.constructor( *constructor_args, **constructor_kwargs) # # Transmit the deployment tx # # receipt = self.send_transaction(contract_function=transaction_function, sender_address=deployer_address, payload=deploy_transaction) # # Verify deployment success # # Success address = receipt['contractAddress'] self.log.info( f"Confirmed {contract_name}:{contract_factory.version} deployment: new address {address}" ) # # Instantiate & Enroll contract # contract = self.client.w3.eth.contract( address=address, abi=contract_factory.abi, version=contract_factory.version, ContractFactoryClass=self._contract_factory) if enroll is True: registry.enroll(contract_name=contract_name, contract_address=contract.address, contract_abi=contract.abi, contract_version=contract.version) return contract, receipt # receipt
def get_contract_by_name( self, registry: BaseContractRegistry, name: str, version: int = None, proxy_name: str = None, use_proxy_address: bool = True) -> Union[Contract, List[tuple]]: """ Instantiate a deployed contract from registry data, and assimilate it with its proxy if it is upgradeable, or return all registered records if use_proxy_address is False. """ target_contract_records = registry.search(contract_name=name) if not target_contract_records: raise self.UnknownContract( f"No such contract records with name {name}.") if proxy_name: # Lookup proxies; Search for a published proxy that targets this contract record proxy_records = registry.search(contract_name=proxy_name) results = list() for proxy_name, proxy_addr, proxy_abi in proxy_records: proxy_contract = self.client.w3.eth.contract( abi=proxy_abi, address=proxy_addr, ContractFactoryClass=self._contract_factory) # Read this dispatcher's target address from the blockchain proxy_live_target_address = proxy_contract.functions.target( ).call() for target_name, target_addr, target_abi in target_contract_records: if target_addr == proxy_live_target_address: if use_proxy_address: pair = (proxy_addr, target_abi) else: pair = (target_addr, target_abi) else: continue results.append(pair) if len(results) > 1: address, abi = results[0] message = "Multiple {} deployments are targeting {}".format( proxy_name, address) raise self.InterfaceError(message.format(name)) else: try: selected_address, selected_abi = results[0] except IndexError: raise self.UnknownContract( f"There are no Dispatcher records targeting '{name}'") else: # NOTE: 0 must be allowed as a valid version number if len(target_contract_records) != 1: if version is None: m = f"{len(target_contract_records)} records enrolled for contract {name} " \ f"and no version index was supplied." raise self.InterfaceError(m) version = self.__get_version_index( name=name, version_index=version, enrollments=len(target_contract_records)) else: version = -1 # default _target_contract_name, selected_address, selected_abi = target_contract_records[ version] # Create the contract from selected sources unified_contract = self.client.w3.eth.contract( abi=selected_abi, address=selected_address, ContractFactoryClass=self._contract_factory) return unified_contract