def create_bidder(self, registry, hw_wallet: bool = False): signer = Signer.from_signer_uri( self.signer_uri) if self.signer_uri else None return self.__create_bidder(registry=registry, signer=signer, hw_wallet=hw_wallet, transacting=True)
def test_signer_reads_keystore_from_disk(mock_account, mock_key, temp_dir_path): # Test reading a keyfile from the disk via KeystoreSigner since # it is mocked for the rest of this test module fake_ethereum = temp_dir_path / '.fake-ethereum' try: fake_ethereum.mkdir() tmp_keystore = temp_dir_path / '.fake-ethereum' / 'keystore' tmp_keystore.mkdir() mock_keyfile_path = tmp_keystore / MOCK_KEYFILE_NAME mock_keyfile_path.touch(exist_ok=True) with open(mock_keyfile_path, 'w') as fake_keyfile: fake_keyfile.write(json.dumps(MOCK_KEYFILE)) mock_keystore_uri = f'keystore://{tmp_keystore}' signer = Signer.from_signer_uri(uri=mock_keystore_uri, testnet=True) assert signer.path == tmp_keystore assert len(signer.accounts) == 1 assert MOCK_KEYFILE['address'] in signer.accounts finally: if fake_ethereum.exists(): shutil.rmtree(fake_ethereum, ignore_errors=True)
def __create_bidder(self, registry, domain: str, transacting: bool = True, hw_wallet: bool = False, ) -> Bidder: is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri) testnet = self.network != NetworksInventory.MAINNET signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet) if self.signer_uri else None password_required = (not is_clef and not hw_wallet) if signer and transacting and password_required: client_password = get_client_password(checksum_address=self.bidder_address) signer.unlock_account(account=self.bidder_address, password=client_password) transacting_power = None if transacting: transacting_power = TransactingPower(account=self.bidder_address, signer=signer) transacting_power.unlock(password=client_password) bidder = Bidder(registry=registry, transacting_power=transacting_power, checksum_address=self.bidder_address if not transacting_power else None, domain=domain) return bidder
def test_create_signer_from_keystore_file(mock_account, mock_keystore): mock_keystore_path = mock_keystore / MOCK_KEYFILE_NAME mock_keystore_uri = f'keystore:{mock_keystore_path}' # Return a "real" account address from the keyfile signer = Signer.from_signer_uri(uri=mock_keystore_uri, testnet=True) # type: KeystoreSigner assert signer.path == str(mock_keystore_path) assert len(signer.accounts) == 1 assert mock_account.address in signer.accounts
def test_create_signer_from_keystore_directory(mock_account, mock_keystore): mock_keystore_path = mock_keystore mock_keystore_uri = f'keystore:{mock_keystore_path}' # Return a "real" account address from the keyfile signer = Signer.from_signer_uri(uri=mock_keystore_uri, testnet=True) # type: KeystoreSigner assert signer.path == mock_keystore_path assert len(signer.accounts) == 1 assert mock_account.address in signer.accounts
def good_signer(mock_account, mock_keystore): # Return a "real" account address from the keyfile mock_keystore_uri = f'keystore:{mock_keystore}' signer = Signer.from_signer_uri(uri=mock_keystore_uri) # type: KeystoreSigner # unlock signer.unlock_account(account=mock_account.address, password=INSECURE_DEVELOPMENT_PASSWORD) return signer
def unbond(registry_filepath, eth_provider_uri, signer_uri, staking_provider, network, force): """Unbonds an operator from an authorized staking provider.""" # # Setup # emitter = StdoutEmitter() if not signer_uri: emitter.message('--signer is required', color='red') raise click.Abort() if not network: network = select_network(emitter=emitter, network_type=NetworksInventory.ETH) connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter) registry = get_registry(network=network, registry_filepath=registry_filepath) agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry) signer = Signer.from_signer_uri(signer_uri) transacting_power = TransactingPower(account=staking_provider, signer=signer) # # Check # bonded, onchain_operator_address = is_bonded( agent=agent, staking_provider=staking_provider, return_address=True) if not bonded: emitter.message(NOT_BONDED.format(provider=staking_provider), color='red') raise click.Abort() check_bonding_requirements(emitter=emitter, agent=agent, staking_provider=staking_provider) # # Unbond # if not force: click.confirm(CONFIRM_UNBONDING.format( provider=staking_provider, operator=onchain_operator_address), abort=True) transacting_power.unlock(password=get_client_password( checksum_address=staking_provider, envvar=NUCYPHER_ENVVAR_STAKING_PROVIDER_ETH_PASSWORD)) emitter.echo(UNBONDING.format(operator=onchain_operator_address)) receipt = agent.bond_operator(operator=NULL_ADDRESS, transacting_power=transacting_power, staking_provider=staking_provider) paint_receipt_summary(receipt=receipt, emitter=emitter)
def dynamic_payload(self) -> dict: """Exported dynamic configuration values for initializing Ursula""" payload = dict() if not self.federated_only: payload.update(dict(registry=self.registry, signer=Signer.from_signer_uri(self.signer_uri))) payload.update(dict(network_middleware=self.network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE(), known_nodes=self.known_nodes, node_storage=self.node_storage, crypto_power_ups=self.derive_node_power_ups())) return payload
def test_create_signer(mocker, mock_listdir, mock_account, mock_key): # Return a "real" account address from the keyfile mock_keyfile_reader = mocker.patch.object(KeystoreSigner, '_KeystoreSigner__read_keyfile', autospec=True) mock_keyfile_reader.return_value = mock_account.address, dict( address=mock_account.address) signer = Signer.from_signer_uri( uri=MOCK_KEYSTORE_URI) # type: KeystoreSigner assert signer.path == MOCK_KEYSTORE_PATH assert len(signer.accounts) == 1 assert mock_account.address in signer.accounts
def test_invalid_keystore(mocker, mock_listdir): # mock Keystoresigner.__read_keyfile # Invalid keystore values and exception handling mock_keyfile_reader = mocker.patch.object(KeystoreSigner, '_KeystoreSigner__read_keyfile', autospec=True) mock_keyfile_reader.return_value = '0xdeadbeef', dict() # # 1 - Create # with pytest.raises(KeystoreSigner.InvalidKeyfile) as e: Signer.from_signer_uri(uri=MOCK_KEYSTORE_URI) assert "does not contain a valid ethereum address" in str(e.value) # Invalid keyfiles for exception in (FileNotFoundError, KeyError): with pytest.raises(KeystoreSigner.InvalidKeyfile): mock_keyfile_reader.side_effect = exception Signer.from_signer_uri(uri=MOCK_KEYSTORE_URI) mock_keyfile_reader.side_effect = None # clean up this mess
def __create_bidder(self, registry, transacting: bool = True, hw_wallet: bool = False) -> Bidder: client_password = None is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri) if transacting and not is_clef and not hw_wallet: client_password = get_client_password(checksum_address=self.bidder_address) signer = Signer.from_signer_uri(self.signer_uri) if self.signer_uri else None bidder = Bidder(checksum_address=self.bidder_address, registry=registry, client_password=client_password, signer=signer, transacting=transacting) return bidder
def good_signer(mocker, mock_account, mock_key): # Return a "real" account address from the keyfile mock_keyfile_reader = mocker.patch.object(KeystoreSigner, '_KeystoreSigner__read_keyfile', autospec=True) mock_keyfile_reader.return_value = mock_account.address, dict( address=mock_account.address) signer = Signer.from_signer_uri( uri=MOCK_KEYSTORE_URI) # type: KeystoreSigner # unlock mock_decrypt = mocker.patch.object(Account, 'decrypt', autospec=True) mock_decrypt.return_value = mock_key.privateKey signer.unlock_account(account=mock_account.address, password=INSECURE_DEVELOPMENT_PASSWORD) return signer
def test_invalid_keystore(tmp_path): with pytest.raises(Signer.InvalidSignerURI) as e: Signer.from_signer_uri(uri=f'keystore:{tmp_path/"nonexistent"}', testnet=True) empty_path = tmp_path / 'empty_file' open(empty_path, 'x+t').close() with pytest.raises(KeystoreSigner.InvalidKeyfile, match= 'Invalid JSON in keyfile at') as e: Signer.from_signer_uri(uri=f'keystore:{empty_path}', testnet=True) empty_json = tmp_path / 'empty_json' json.dump({}, open(empty_json, 'x+t')) with pytest.raises(KeystoreSigner.InvalidKeyfile, match= 'Keyfile does not contain address field at') as e: Signer.from_signer_uri(uri=f'keystore:{empty_json}', testnet=True) bad_address = tmp_path / 'bad_address' json.dump({'address':''}, open(bad_address, 'x+t')) with pytest.raises(KeystoreSigner.InvalidKeyfile, match= 'does not contain a valid ethereum address') as e: Signer.from_signer_uri(uri=f'keystore:{bad_address}', testnet=True)
def dynamic_payload(self) -> dict: payload = dict(registry=self.registry, signer=Signer.from_signer_uri(self.signer_uri)) return payload
def dynamic_payload(self) -> dict: testnet = self.domain != NetworksInventory.MAINNET signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet) payload = dict(registry=self.registry, signer=signer) return payload
def test_blank_keystore_uri(): with pytest.raises(Signer.InvalidSignerURI) as error: Signer.from_signer_uri(uri='keystore://') # it's blank! assert 'Blank signer URI - No keystore path provided' in str(error)
def create_actor(self, emitter, is_multisig: bool = False): _ensure_config_root(self.config_root) deployer_interface = _initialize_blockchain( poa=self.poa, provider_uri=self.provider_uri, emitter=emitter, ignore_solidity_check=self.ignore_solidity_check, gas_strategy=self.gas_strategy) # Warnings _pre_launch_warnings(emitter, self.etherscan, self.hw_wallet) # # Establish Registry # local_registry = establish_deployer_registry( emitter=emitter, use_existing_registry=bool(self.contract_name), registry_infile=self.registry_infile, registry_outfile=self.registry_outfile, dev=self.dev) # # Make Authenticated Deployment Actor # # Verify Address & collect password password = None if is_multisig: multisig_agent = ContractAgency.get_agent(MultiSigAgent, registry=local_registry) deployer_address = multisig_agent.contract.address is_transacting = False else: is_transacting = True deployer_address = self.deployer_address if not deployer_address: prompt = "Select deployer account" deployer_address = select_client_account( emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, signer_uri=self.signer_uri, show_eth_balance=True) if not self.force: click.confirm( "Selected {} - Continue?".format(deployer_address), abort=True) if not self.hw_wallet and not deployer_interface.client.is_local: password = get_client_password( checksum_address=deployer_address) # Produce Actor signer = Signer.from_signer_uri( self.signer_uri) if self.signer_uri else None ADMINISTRATOR = ContractAdministrator( registry=local_registry, client_password=password, deployer_address=deployer_address, is_transacting=is_transacting, signer=signer, staking_escrow_test_mode=self.se_test_mode) # Verify ETH Balance emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}") if is_transacting and ADMINISTRATOR.eth_balance == 0: emitter.echo("Deployer address has no ETH.", color='red', bold=True) raise click.Abort() return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
def select_client_account(emitter, provider_uri: str = None, signer_uri: str = None, wallet: Wallet = None, prompt: str = None, default: int = 0, registry=None, show_eth_balance: bool = False, show_nu_balance: bool = False, show_staking: bool = False, network: str = None, poa: bool = None) -> str: """ Note: Showing ETH and/or NU balances, causes an eager blockchain connection. """ # We use Wallet internally as an account management abstraction if not wallet: if not provider_uri and not signer_uri: raise ValueError( "At least a provider URI or signer URI is necessary to select an account" ) # Lazy connect the blockchain interface if not BlockchainInterfaceFactory.is_interface_initialized( provider_uri=provider_uri): BlockchainInterfaceFactory.initialize_interface( provider_uri=provider_uri, poa=poa, emitter=emitter) signer = Signer.from_signer_uri(signer_uri) if signer_uri else None wallet = Wallet(provider_uri=provider_uri, signer=signer) elif provider_uri or signer_uri: raise ValueError( "If you input a wallet, don't pass a provider URI or signer URI too" ) # Display accounts info if show_nu_balance or show_staking: # Lazy registry fetching if not registry: registry = InMemoryContractRegistry.from_latest_publication( network=network) wallet_accounts = wallet.accounts enumerated_accounts = dict(enumerate(wallet_accounts)) if len(enumerated_accounts) < 1: emitter.echo("No ETH accounts were found.", color='red', bold=True) raise click.Abort() # Display account info headers = ['Account'] if show_staking: headers.append('Staking') if show_eth_balance: headers.append('ETH') if show_nu_balance: headers.append('NU') rows = list() for index, account in enumerated_accounts.items(): row = [account] if show_staking: staker = Staker(is_me=True, checksum_address=account, registry=registry) staker.stakes.refresh() is_staking = 'Yes' if bool(staker.stakes) else 'No' row.append(is_staking) if show_eth_balance: ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether') row.append(f'{ether_balance} ETH') if show_nu_balance: token_balance = NU.from_nunits( wallet.token_balance(account, registry)) row.append(token_balance) rows.append(row) emitter.echo(tabulate(rows, headers=headers, showindex='always')) # Prompt the user for selection, and return prompt = prompt or "Select index of account" account_range = click.IntRange(min=0, max=len(enumerated_accounts) - 1) choice = click.prompt(prompt, type=account_range, default=default) chosen_account = enumerated_accounts[choice] emitter.echo(f"Selected {choice}: {chosen_account}", color='blue') return chosen_account
def create_actor( self, emitter: StdoutEmitter, is_multisig: bool = False ) -> Tuple[ContractAdministrator, str, BlockchainInterface, BaseContractRegistry]: ensure_config_root(self.config_root) deployer_interface = initialize_deployer_interface( poa=self.poa, provider_uri=self.provider_uri, emitter=emitter, ignore_solidity_check=self.ignore_solidity_check, gas_strategy=self.gas_strategy) # Warnings deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet) # # Establish Registry # local_registry = establish_deployer_registry( emitter=emitter, use_existing_registry=bool(self.contract_name), registry_infile=self.registry_infile, registry_outfile=self.registry_outfile, dev=self.dev) # # Make Authenticated Deployment Actor # # Verify Address & collect password password = None if is_multisig: multisig_agent = ContractAgency.get_agent(MultiSigAgent, registry=local_registry) deployer_address = multisig_agent.contract.address is_transacting = False else: is_transacting = True deployer_address = self.deployer_address if not deployer_address: deployer_address = select_client_account( emitter=emitter, prompt=SELECT_DEPLOYER_ACCOUNT, provider_uri=self.provider_uri, signer_uri=self.signer_uri, show_eth_balance=True) if not self.force: click.confirm( CONFIRM_SELECTED_ACCOUNT.format(address=deployer_address), abort=True) is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri) eth_password_is_needed = not self.hw_wallet and not deployer_interface.client.is_local and not is_clef if eth_password_is_needed: password = get_client_password( checksum_address=deployer_address) # Produce Actor signer = Signer.from_signer_uri( self.signer_uri) if self.signer_uri else None ADMINISTRATOR = ContractAdministrator( registry=local_registry, client_password=password, deployer_address=deployer_address, is_transacting=is_transacting, signer=signer, staking_escrow_test_mode=self.se_test_mode) # Verify ETH Balance emitter.echo( DEPLOYER_BALANCE.format(eth_balance=ADMINISTRATOR.eth_balance)) if is_transacting and ADMINISTRATOR.eth_balance == 0: emitter.echo(DEPLOYER_ADDRESS_ZERO_ETH, color='red', bold=True) raise click.Abort() return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
L1_NETWORK = 'mainnet' # 'ibex' L2_NETWORK = 'polygon' # 'mumbai' ####################################### # Alicia, the Authority of the Policy # ####################################### connect_web3_provider( eth_provider_uri=L1_PROVIDER) # Connect to the ethereum provider. connect_web3_provider( eth_provider_uri=L2_PROVIDER) # Connect to the layer 2 provider. # Setup and unlock alice's ethereum wallet. # WARNING: Never give your mainnet password or mnemonic phrase to anyone. # Do not use mainnet keys, create a dedicated software wallet to use for this demo. wallet = Signer.from_signer_uri(SIGNER_URI) password = os.environ.get('DEMO_ALICE_PASSWORD') or getpass( f"Enter password to unlock Alice's wallet ({ALICE_ADDRESS[:8]}): ") wallet.unlock_account(account=ALICE_ADDRESS, password=password) # This is Alice's payment method. payment_method = SubscriptionManagerPayment(network=L2_NETWORK, eth_provider=L2_PROVIDER) # This is Alicia. alicia = Alice(checksum_address=ALICE_ADDRESS, signer=wallet, domain=L1_NETWORK, eth_provider_uri=L1_PROVIDER, payment_method=payment_method)
def select_client_account(emitter, provider_uri: str = None, signer: Signer = None, signer_uri: str = None, wallet: Wallet = None, prompt: str = None, default: int = 0, registry=None, show_eth_balance: bool = False, show_nu_balance: bool = False, show_staking: bool = False, network: str = None, poa: bool = None ) -> str: """ Interactively select an ethereum wallet account from a table of nucypher account metadata. Note: Showing ETH and/or NU balances, causes an eager blockchain connection. """ if wallet and (provider_uri or signer_uri or signer): raise ValueError("If a wallet is provided, don't provide a signer, provider URI, or signer URI.") # We use Wallet internally as an account management abstraction if not wallet: if signer and signer_uri: raise ValueError('Pass either signer or signer_uri but not both.') if not provider_uri and not signer_uri: raise ValueError("At least a provider URI or signer URI is necessary to select an account") if provider_uri: # Lazy connect the blockchain interface if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri): BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri, poa=poa, emitter=emitter) if signer_uri: signer = Signer.from_signer_uri(signer_uri) wallet = Wallet(provider_uri=provider_uri, signer=signer) # Display accounts info if show_nu_balance or show_staking: # Lazy registry fetching if not registry: if not network: raise ValueError("Pass network name or registry; Got neither.") registry = InMemoryContractRegistry.from_latest_publication(network=network) wallet_accounts = wallet.accounts enumerated_accounts = dict(enumerate(wallet_accounts)) if len(enumerated_accounts) < 1: emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True) raise click.Abort() # Display account info headers = ['Account'] if show_staking: headers.append('Staking') if show_eth_balance: headers.append('ETH') if show_nu_balance: headers.append('NU') rows = list() for index, account in enumerated_accounts.items(): row = [account] if show_staking: staker = Staker(is_me=True, checksum_address=account, registry=registry) staker.stakes.refresh() is_staking = 'Yes' if bool(staker.stakes) else 'No' row.append(is_staking) if show_eth_balance: ether_balance = Web3.fromWei(wallet.eth_balance(account), 'ether') row.append(f'{ether_balance} ETH') if show_nu_balance: token_balance = NU.from_nunits(wallet.token_balance(account, registry)) row.append(token_balance) rows.append(row) emitter.echo(tabulate(rows, headers=headers, showindex='always')) # Prompt the user for selection, and return prompt = prompt or GENERIC_SELECT_ACCOUNT account_range = click.IntRange(min=0, max=len(enumerated_accounts)-1) choice = click.prompt(prompt, type=account_range, default=default) chosen_account = enumerated_accounts[choice] emitter.echo(SELECTED_ACCOUNT.format(choice=choice, chosen_account=chosen_account), color='blue') return chosen_account
def test_trezor_signer_creation_from_uri(mock_trezor, simple_trezor_uri): signer = Signer.from_signer_uri(uri=simple_trezor_uri, testnet=False) assert isinstance(signer, TrezorSigner) assert len(signer.accounts) == 1 del signer
def test_blank_keystore_uri(): with pytest.raises( Signer.InvalidSignerURI, match='Blank signer URI - No keystore path provided') as error: Signer.from_signer_uri(uri='keystore://', testnet=True) # it's blank!
def __init__( self, # Base emitter=None, config_root: Optional[Path] = None, filepath: Optional[Path] = None, # Mode dev_mode: bool = False, federated_only: bool = False, # Identity checksum_address: str = None, crypto_power: CryptoPower = None, # Keystore keystore: Keystore = None, keystore_path: Optional[Path] = None, # Learner learn_on_same_thread: bool = False, abort_on_learning_error: bool = False, start_learning_now: bool = True, # Network controller_port: int = None, domain: str = DEFAULT_DOMAIN, network_middleware: RestMiddleware = None, lonely: bool = False, # Node Storage known_nodes: set = None, node_storage: NodeStorage = None, reload_metadata: bool = True, save_metadata: bool = True, # Blockchain poa: bool = None, light: bool = False, provider_uri: str = None, gas_strategy: Union[Callable, str] = DEFAULT_GAS_STRATEGY, max_gas_price: Optional[int] = None, signer_uri: str = None, # Registry registry: BaseContractRegistry = None, registry_filepath: Optional[Path] = None, # Deployed Workers worker_data: dict = None): self.log = Logger(self.__class__.__name__) # This constant is used to signal that a path can be generated if one is not provided. UNINITIALIZED_CONFIGURATION.bool_value(False) # Identity # NOTE: NodeConfigurations can only be used with Self-Characters self.is_me = True self.checksum_address = checksum_address # Keystore self.crypto_power = crypto_power if keystore_path and not keystore: keystore = Keystore(keystore_path=keystore_path) self.__keystore = self.__keystore = keystore or NO_KEYSTORE_ATTACHED.bool_value( False) self.keystore_dir = Path( keystore.keystore_path ).parent if keystore else UNINITIALIZED_CONFIGURATION # Contract Registry if registry and registry_filepath: if registry.filepath != registry_filepath: error = f"Inconsistent registry filepaths for '{registry.filepath.absolute()}'" \ f" and '{registry_filepath.absolute()}'." raise ValueError(error) else: self.log.warn( f"Registry and registry filepath were both passed.") self.registry = registry or NO_BLOCKCHAIN_CONNECTION.bool_value(False) self.registry_filepath = registry_filepath or UNINITIALIZED_CONFIGURATION # Blockchain self.poa = poa self.is_light = light self.provider_uri = provider_uri or NO_BLOCKCHAIN_CONNECTION self.signer_uri = signer_uri or None # Learner self.federated_only = federated_only self.domain = domain self.learn_on_same_thread = learn_on_same_thread self.abort_on_learning_error = abort_on_learning_error self.start_learning_now = start_learning_now self.save_metadata = save_metadata self.reload_metadata = reload_metadata self.known_nodes = known_nodes or set() # handpicked self.lonely = lonely # Configuration self.__dev_mode = dev_mode self.config_file_location = filepath or UNINITIALIZED_CONFIGURATION self.config_root = UNINITIALIZED_CONFIGURATION # Deployed Workers self.worker_data = worker_data # # Federated vs. Blockchain arguments consistency # # # Federated # if self.federated_only: # Check for incompatible values blockchain_args = { 'filepath': registry_filepath, 'poa': poa, 'provider_uri': provider_uri, 'gas_strategy': gas_strategy, 'max_gas_price': max_gas_price } if any(blockchain_args.values()): bad_args = ", ".join(f"{arg}={val}" for arg, val in blockchain_args.items() if val) self.log.warn( f"Arguments {bad_args} are incompatible with federated_only. " f"Overridden with a sane default.") # Clear decentralized attributes to ensure consistency with a # federated configuration. self.poa = False self.is_light = False self.provider_uri = None self.registry_filepath = None self.gas_strategy = None self.max_gas_price = None # # Decentralized # else: self.gas_strategy = gas_strategy self.max_gas_price = max_gas_price # gwei is_initialized = BlockchainInterfaceFactory.is_interface_initialized( provider_uri=self.provider_uri) if not is_initialized and provider_uri: BlockchainInterfaceFactory.initialize_interface( provider_uri=self.provider_uri, poa=self.poa, light=self.is_light, emitter=emitter, gas_strategy=self.gas_strategy, max_gas_price=self.max_gas_price) else: self.log.warn( f"Using existing blockchain interface connection ({self.provider_uri})." ) if not self.registry: # TODO: These two code blocks are untested. if not self.registry_filepath: # TODO: Registry URI (goerli://speedynet.json) :-) self.log.info(f"Fetching latest registry from source.") self.registry = InMemoryContractRegistry.from_latest_publication( network=self.domain) else: self.registry = LocalContractRegistry( filepath=self.registry_filepath) self.log.info(f"Using local registry ({self.registry}).") self.testnet = self.domain != NetworksInventory.MAINNET self.signer = Signer.from_signer_uri(self.signer_uri, testnet=self.testnet) if dev_mode: self.__temp_dir = UNINITIALIZED_CONFIGURATION self._setup_node_storage() self.initialize(password=DEVELOPMENT_CONFIGURATION) else: self.__temp_dir = LIVE_CONFIGURATION self.config_root = config_root or self.DEFAULT_CONFIG_ROOT self._cache_runtime_filepaths() self._setup_node_storage(node_storage=node_storage) # Network self.controller_port = controller_port or self.DEFAULT_CONTROLLER_PORT self.network_middleware = network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE( registry=self.registry) super().__init__(filepath=self.config_file_location, config_root=self.config_root)
def bond(registry_filepath, eth_provider_uri, signer_uri, operator_address, staking_provider, network, force): """ Bond an operator to a staking provider. The staking provider must be authorized to use the PREApplication. """ # # Setup # emitter = StdoutEmitter() connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter) if not signer_uri: emitter.message('--signer is required', color='red') raise click.Abort() if not network: network = select_network(emitter=emitter) signer = Signer.from_signer_uri(signer_uri) transacting_power = TransactingPower(account=staking_provider, signer=signer) registry = get_registry(network=network, registry_filepath=registry_filepath) agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry) # # Checks # # Check for authorization is_authorized(emitter=emitter, agent=agent, staking_provider=staking_provider) # Check bonding if is_bonded(agent=agent, staking_provider=staking_provider, return_address=False): # operator is already set - check timing check_bonding_requirements(emitter=emitter, agent=agent, staking_provider=staking_provider) # Check for pre-existing staking providers for this operator onchain_staking_provider = agent.get_staking_provider_from_operator( operator_address=operator_address) if onchain_staking_provider != NULL_ADDRESS: emitter.message(ALREADY_BONDED.format( provider=onchain_staking_provider, operator=operator_address), color='red') raise click.Abort() # dont steal bananas # Check that operator is not human if staking_provider != operator_address: # if the operator has a beneficiary it is the staking provider. beneficiary = agent.get_beneficiary(staking_provider=operator_address) if beneficiary != NULL_ADDRESS: emitter.message(UNEXPECTED_HUMAN_OPERATOR, color='red') raise click.Abort() # # Bond # if not force: click.confirm(CONFIRM_BONDING.format(provider=staking_provider, operator=operator_address), abort=True) transacting_power.unlock(password=get_client_password( checksum_address=staking_provider, envvar=NUCYPHER_ENVVAR_STAKING_PROVIDER_ETH_PASSWORD)) emitter.echo(BONDING.format(operator=operator_address)) receipt = agent.bond_operator(operator=operator_address, transacting_power=transacting_power, staking_provider=staking_provider) paint_receipt_summary(receipt=receipt, emitter=emitter)