def test_select_client_account_valid_sources(mocker, mock_stdin, test_emitter, mock_testerchain, patch_keystore, mock_accounts, selection, capsys): # From External Signer mock_stdin.line(str(selection)) mock_signer = mocker.patch.object(KeystoreSigner, 'from_signer_uri', return_value=Web3Signer( mock_testerchain.client)) selected_account = select_client_account(emitter=test_emitter, signer_uri=MOCK_SIGNER_URI) expected_account = mock_testerchain.client.accounts[selection] assert selected_account == expected_account mock_signer.assert_called_once_with(uri=MOCK_SIGNER_URI, testnet=True) assert mock_stdin.empty() captured = capsys.readouterr() assert GENERIC_SELECT_ACCOUNT in captured.out and f"Selected {selection}" in captured.out # From Wallet mock_stdin.line(str(selection)) expected_account = mock_testerchain.client.accounts[selection] selected_account = select_client_account(emitter=test_emitter, signer=Web3Signer( mock_testerchain.client)) assert selected_account == expected_account assert mock_stdin.empty() captured = capsys.readouterr() assert GENERIC_SELECT_ACCOUNT in captured.out and f"Selected {selection}" in captured.out # From pre-initialized Provider mock_stdin.line(str(selection)) expected_account = mock_testerchain.client.accounts[selection] selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI) assert selected_account == expected_account assert mock_stdin.empty() captured = capsys.readouterr() assert GENERIC_SELECT_ACCOUNT in captured.out and f"Selected {selection}" in captured.out # From uninitialized Provider mock_stdin.line(str(selection)) mocker.patch.object(BlockchainInterfaceFactory, 'is_interface_initialized', return_value=False) mocker.patch.object(BlockchainInterfaceFactory, '_interfaces', return_value={}) mocker.patch.object(BlockchainInterfaceFactory, 'get_interface', return_value=mock_testerchain) selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI) assert selected_account == expected_account assert mock_stdin.empty() captured = capsys.readouterr() assert GENERIC_SELECT_ACCOUNT in captured.out and f"Selected {selection}" in captured.out
def test_select_client_account_with_no_accounts( mocker, mock_stdin, # used to assert the user was not prompted test_emitter, mock_testerchain, capsys): mocker.patch.object(EthereumClient, 'accounts', return_value=[]) with pytest.raises(click.Abort): select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI) captured = capsys.readouterr() assert NO_ETH_ACCOUNTS in captured.out
def generate_config(self, emitter: StdoutEmitter, config_root: str) -> AliceConfiguration: opts = self.config_options if opts.dev: raise click.BadArgumentUsage("Cannot create a persistent development character") if not opts.provider_uri and not opts.federated_only: raise click.BadOptionUsage( option_name='--provider', message="--provider is required to create a new decentralized alice.") pay_with = opts.pay_with if not pay_with and not opts.federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, show_eth_balance=True, network=opts.domain) return AliceConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=pay_with, domain=opts.domain, federated_only=opts.federated_only, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, registry_filepath=opts.registry_filepath, poa=self.poa, light=self.light, m=self.m, n=self.n, duration_periods=self.duration_periods)
def sign(general_config, blockchain_options, multisig_options, proposal): """ Sign a proposed transaction before being sent to the MultiSig contract for execution """ # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = get_registry(network=blockchain_options.network) proposal = Proposal.from_file(proposal) if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account(emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) name, version, address, abi = registry.search(contract_address=proposal.target_address) # TODO: This assumes that we're always signing proxy retargetting. For the moment is true. proxy_contract = blockchain.client.w3.eth.contract(abi=abi, address=address, version=version, ContractFactoryClass=blockchain._CONTRACT_FACTORY) paint_multisig_proposed_transaction(emitter, proposal, proxy_contract) click.confirm(PROMPT_CONFIRM_MULTISIG_SIGNATURE, abort=True) executive = multisig_options.create_transactingless_executive(registry) # FIXME: Since we use a signer, don't ask for PW authorization = executive.authorize_proposal(proposal) emitter.echo(MULTISIG_SIGNATURE_RECEIVED.format(recovered_address=authorization.recover_executive_address(proposal))) emitter.echo(f"{authorization.serialize().hex()}\n", bold=True, color='green')
def get_bidder_address(self, emitter, registry): if not self.bidder_address: self.bidder_address = select_client_account(emitter=emitter, provider_uri=self.provider_uri, signer_uri=self.signer_uri, network=self.network, registry=registry, show_eth_balance=True) return self.bidder_address
def test_select_client_account_ambiguous_source( mock_stdin, # used to assert the user was not prompted test_emitter, mock_testerchain): # # Implicit wallet # TODO: Are all cases covered? # error_message = "At least a provider URI, signer URI or signer must be provided to select an account" with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter) error_message = "Pass either signer or signer_uri but not both." with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter, signer=Mock(), signer_uri=MOCK_SIGNER_URI)
def get_participant_address(self, emitter, registry, show_staking: bool = False): if not self.participant_address: self.participant_address = select_client_account(emitter=emitter, provider_uri=self.provider_uri, signer_uri=self.signer_uri, network=self.network, registry=registry, show_eth_balance=True, show_nu_balance=False, show_staking=show_staking) return self.participant_address
def test_select_client_account_ambiguous_source( mock_stdin, # used to assert the user was not prompted test_emitter, mock_testerchain): # # Implicit wallet # error_message = "At least a provider URI or signer URI is necessary to select an account" with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter) error_message = "Pass either signer or signer_uri but not both." with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter, signer=Mock(), signer_uri=MOCK_SIGNER_URI) # # Explicit wallet # error_message = "If a wallet is provided, don't provide a signer, provider URI, or signer URI." with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter, signer_uri=Mock(), wallet=Mock()) with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter, signer=Mock(), wallet=Mock()) with pytest.raises(ValueError, match=error_message): select_client_account(emitter=test_emitter, provider_uri=Mock(), wallet=Mock())
def propose(general_config, blockchain_options, multisig_options): """Create a proposal of MultiSig transaction""" # TODO: Extend this command to cover this list of proposals # - Add new MultiSig owner # - Remove MultiSig owner # - Change threshold of MultiSig # - Upgrade contract (in particular, retarget to a deployed one) # - Transfer ownership of contract # - Send ETH from MultiSig # - Send tokens from MultiSig # - Change global fee range in PolicyManager # - Send raw transaction # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) # TODO: Review this commented out line blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = get_registry(network=blockchain_options.network) if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account( emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) # FIXME: Unexpected input trustee = multisig_options.create_transactingless_trustee(registry) # As a PoC, this command only allows to change the threshold # TODO: Think in the UX for choosing between different types of proposals new_threshold = click.prompt(PROMPT_NEW_MULTISIG_THRESHOLD, type=click.INT) proposal = trustee.propose_changing_threshold(new_threshold) paint_multisig_proposed_transaction(emitter=emitter, proposal=proposal, registry=registry) filepath = Path( f'proposal-changeThreshold-{trustee.multisig_agent.contract_address[:8]}-TX-{proposal.nonce}.json' ) proposal.write(filepath=filepath) emitter.echo( SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True)
def test_select_client_account(mock_stdin, test_emitter, mock_testerchain, selection, capsys): """Fine-grained assertions about the return value of interactive client account selection""" mock_stdin.line(str(selection)) expected_account = mock_testerchain.client.accounts[selection] selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI) assert selected_account, "Account selection returned Falsy instead of an address" assert isinstance(selected_account, str), "Selection is not a str" assert is_checksum_address( selected_account), "Selection is not a valid checksum address" assert selected_account == expected_account, "Selection returned the wrong address" assert mock_stdin.empty() captured = capsys.readouterr() assert GENERIC_SELECT_ACCOUNT in captured.out
def execute(general_config, blockchain_options, multisig_options, proposal): """ Collect authorizations from executives and execute transaction through MultiSig contract """ # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = get_registry(network=blockchain_options.network) proposal = Proposal.from_file(proposal) if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account( emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) # FIXME: Unexpected argument!! name, version, address, abi = registry.search( contract_address=proposal.target_address) # TODO: This assumes that we're always signing proxy retargetting. For the moment is true. proxy_contract = blockchain.client.w3.eth.contract( abi=abi, address=address, version=version, ContractFactoryClass=blockchain._CONTRACT_FACTORY) paint_multisig_proposed_transaction(emitter, proposal, proxy_contract) trustee = multisig_options.create_trustee(registry) threshold = trustee.multisig_agent.threshold while len(trustee.authorizations) < threshold: auth_hex = click.prompt(PROMPT_FOR_RAW_SIGNATURE, type=click.STRING) authorization = Authorization.from_hex(auth_hex) executive_address = trustee.add_authorization(authorization, proposal) emitter.echo(SUCCESSFUL_MULTISIG_AUTHORIZATION.format( executive_address=executive_address), color='green') click.confirm(CONFIRM_EXECUTE_MULTISIG_TRANSACTION, abort=True) receipt = trustee.execute(proposal) paint_receipt_summary(emitter, receipt)
def generate_config(self, emitter: StdoutEmitter, config_root: Path, key_material: str) -> AliceConfiguration: opts = self.config_options if opts.dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not opts.eth_provider_uri and not opts.federated_only: raise click.BadOptionUsage( option_name='--eth-provider', message=click.style( "--eth-provider is required to create a new decentralized alice.", fg="red")) pay_with = opts.pay_with if not pay_with and not opts.federated_only: pay_with = select_client_account( emitter=emitter, eth_provider_uri=opts.eth_provider_uri, signer_uri=opts.signer_uri, show_eth_balance=True, network=opts.domain) return AliceConfiguration.generate( password=get_nucypher_password(emitter=emitter, confirm=True), key_material=bytes.fromhex(key_material) if key_material else None, config_root=config_root, checksum_address=pay_with, domain=opts.domain, federated_only=opts.federated_only, eth_provider_uri=opts.eth_provider_uri, signer_uri=opts.signer_uri, registry_filepath=opts.registry_filepath, poa=self.poa, light=self.light, threshold=self.threshold, shares=self.shares, duration=self.duration, payment_provider=opts.payment_provider, payment_network=opts.payment_network, payment_method=opts.payment_method, )
def generate_config(self, emitter: StdoutEmitter, config_root: str) -> BobConfiguration: checksum_address = self.checksum_address if not checksum_address and not self.federated_only: checksum_address = select_client_account(emitter=emitter, signer_uri=self.signer_uri, provider_uri=self.provider_uri) # TODO: See #1888 return BobConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=checksum_address, domains=self.domains, federated_only=self.federated_only, registry_filepath=self.registry_filepath, provider_uri=self.provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, )
def generate_config(self, emitter, config_root, force, key_material): if self.dev: raise RuntimeError( 'Persistent configurations cannot be created in development mode.' ) if (not self.operator_address) and not self.federated_only: prompt = "Select operator account" self.operator_address = select_client_account( emitter=emitter, prompt=prompt, eth_provider_uri=self.eth_provider_uri, signer_uri=self.signer_uri) # Resolve rest host if not self.rest_host: self.rest_host = collect_operator_ip_address(emitter, network=self.domain, force=force) return UrsulaConfiguration.generate( password=get_nucypher_password(emitter=emitter, confirm=True), key_material=bytes.fromhex(key_material) if key_material else None, config_root=config_root, rest_host=self.rest_host, rest_port=self.rest_port, db_filepath=self.db_filepath, domain=self.domain, federated_only=self.federated_only, operator_address=self.operator_address, registry_filepath=self.registry_filepath, policy_registry_filepath=self.policy_registry_filepath, eth_provider_uri=self.eth_provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, max_gas_price=self.max_gas_price, poa=self.poa, light=self.light, availability_check=self.availability_check, payment_method=self.payment_method, payment_provider=self.payment_provider, payment_network=self.payment_network)
def generate_config(self, emitter, config_root, force): if self.dev: raise RuntimeError( 'Persistent configurations cannot be created in development mode.' ) worker_address = self.worker_address if (not worker_address) and not self.federated_only: if not worker_address: prompt = "Select worker account" worker_address = select_client_account( emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, signer_uri=self.signer_uri) rest_host = self.rest_host if not rest_host: rest_host = os.environ.get(NUCYPHER_ENVVAR_WORKER_IP_ADDRESS) if not rest_host: # TODO: Something less centralized... :-( # TODO: Ask Ursulas instead rest_host = determine_external_ip_address(emitter, force=force) return UrsulaConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=self.rest_port, db_filepath=self.db_filepath, domains=self.domains, federated_only=self.federated_only, worker_address=worker_address, registry_filepath=self.registry_filepath, provider_process=self.eth_node, provider_uri=self.provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, poa=self.poa, light=self.light, availability_check=self.availability_check)
def generate_config(self, emitter, config_root, force): if self.dev: raise RuntimeError( 'Persistent configurations cannot be created in development mode.' ) worker_address = self.worker_address if (not worker_address) and not self.federated_only: if not worker_address: prompt = "Select worker account" worker_address = select_client_account( emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, signer_uri=self.signer_uri) # Resolve rest host if not self.rest_host: self.rest_host = collect_worker_ip_address(emitter, network=self.domain, force=force) return UrsulaConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=self.rest_host, rest_port=self.rest_port, db_filepath=self.db_filepath, domain=self.domain, federated_only=self.federated_only, worker_address=worker_address, registry_filepath=self.registry_filepath, provider_uri=self.provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, max_gas_price=self.max_gas_price, poa=self.poa, light=self.light, availability_check=self.availability_check)
def generate_config(self, emitter: StdoutEmitter, config_root: Path, key_material: str) -> BobConfiguration: checksum_address = self.checksum_address if not checksum_address and not self.federated_only: checksum_address = select_client_account( emitter=emitter, signer_uri=self.signer_uri, provider_uri=self.provider_uri) # TODO: See #1888 return BobConfiguration.generate( password=get_nucypher_password(emitter=emitter, confirm=True), key_material=bytes.fromhex(key_material) if key_material else None, config_root=config_root, checksum_address=checksum_address, domain=self.domain, federated_only=self.federated_only, registry_filepath=self.registry_filepath, provider_uri=self.provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, max_gas_price=self.max_gas_price, lonely=self.lonely)
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig): """ Upgrade NuCypher existing proxy contract deployments. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, _, registry = actor_options.create_actor( emitter, is_multisig=bool( multisig)) # FIXME: Workaround for building MultiSig TXs contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage( message="--contract-name is required when using --upgrade") if multisig: if not target_address: raise click.BadArgumentUsage( message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(CONFIRM_BUILD_RETARGET_TRANSACTION.format( contract_name=contract_name, target_address=target_address), abort=True) transaction = ADMINISTRATOR.retarget_proxy( contract_name=contract_name, target_address=target_address, just_build_transaction=True) trustee_address = select_client_account( emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_eth_balance=False, show_nu_balance=False, show_staking=False) if not actor_options.force: click.confirm( CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address), abort=True) trustee = Trustee(registry=registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) message = SUCCESSFUL_RETARGET_TX_BUILT.format( contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_multisig_proposed_transaction( emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo( SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True) elif retarget: if not target_address: raise click.BadArgumentUsage( message="--target-address is required when using --retarget") if not actor_options.force: click.confirm(CONFIRM_RETARGET.format( contract_name=contract_name, target_address=target_address), abort=True) receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address) message = SUCCESSFUL_RETARGET.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) else: if not actor_options.force: click.confirm( CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name), abort=True) receipts = ADMINISTRATOR.upgrade_contract( contract_name=contract_name, ignore_deployed=ignore_deployed) emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name), color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt)
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig, confirmations): """Upgrade NuCypher existing proxy contract deployments.""" # # Setup # emitter = general_config.emitter ADMINISTRATOR, deployer_address, blockchain, local_registry = actor_options.create_actor(emitter, is_multisig=bool(multisig)) # FIXME: Workaround for building MultiSig TXs | NRN # # Pre-flight # contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade") try: # Check contract name exists Deployer = ADMINISTRATOR.deployers[contract_name] except KeyError: message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name, constants=ADMINISTRATOR.deployers.keys()) emitter.echo(message, color='red', bold=True) raise click.Abort() deployer = Deployer(registry=local_registry) # Check deployer address is owner if Deployer._ownable and deployer_address != deployer.owner: # blockchain read emitter.echo(DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address, contract_name=contract_name, agent=deployer.make_agent())) raise click.Abort() else: emitter.echo('✓ Verified deployer address as contract owner', color='green') # # Business # if multisig: if not target_address: raise click.BadArgumentUsage(message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(CONFIRM_BUILD_RETARGET_TRANSACTION.format(contract_name=contract_name, target_address=target_address), abort=True) transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address, just_build_transaction=True, confirmations=confirmations) trustee_address = select_client_account(emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_eth_balance=False, show_nu_balance=False, show_staking=False) if not actor_options.force: click.confirm(CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address), abort=True) trustee = Trustee(registry=local_registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) message = SUCCESSFUL_RETARGET_TX_BUILT.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_multisig_proposed_transaction(emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo(SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True) return # Exit elif retarget: if not target_address: raise click.BadArgumentUsage(message="--target-address is required when using --retarget") if not actor_options.force: click.confirm(CONFIRM_RETARGET.format(contract_name=contract_name, target_address=target_address), abort=True) receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,target_address=target_address, confirmations=confirmations) message = SUCCESSFUL_RETARGET.format(contract_name=contract_name, target_address=target_address) emitter.message(message, color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) return # Exit else: github_registry = establish_deployer_registry(emitter=emitter, download_registry=True, network=actor_options.network) if not actor_options.force: # Check for human verification of versioned upgrade details click.confirm(CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name), abort=True) if deployer._ownable: # Only ownable + upgradeable contracts apply verify_upgrade_details(blockchain=blockchain, registry=github_registry, deployer=deployer) # Success receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name, ignore_deployed=ignore_deployed, confirmations=confirmations) emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name), color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt) emitter.echo(REGISTRY_PUBLICATION_HINT.format(contract_name=contract_name, local_registry=local_registry, network=actor_options.network), color='blue') emitter.echo(ETHERSCAN_VERIFY_HINT.format(solc_version=SOLIDITY_COMPILER_VERSION), color='blue') return # Exit
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, max_gas_price=self.max_gas_price) # 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), # TODO: Issue #2314 registry_infile=self.registry_infile, registry_outfile=self.registry_outfile, dev=self.dev, network=self.network) # # 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 testnet = deployer_interface.client.chain_name != PUBLIC_CHAINS[1] # Mainnet signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet) if self.signer_uri else None ADMINISTRATOR = ContractAdministrator(registry=local_registry, client_password=password, deployer_address=deployer_address, is_transacting=is_transacting, signer=signer) # 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
def test_select_client_account_with_balance_display( mock_stdin, test_emitter, mock_testerchain, capsys, test_registry_source_manager, mock_staking_agent, mock_token_agent, selection, show_staking, show_eth, show_tokens, stake_info): # Setup mock_staking_agent.get_all_stakes.return_value = stake_info # Missing network kwarg with balance display active blockchain_read_required = any((show_staking, show_eth, show_tokens)) if blockchain_read_required: with pytest.raises( ValueError, match='Pass network name or registry; Got neither.'): select_client_account(emitter=test_emitter, show_eth_balance=show_eth, show_nu_balance=show_tokens, show_staking=show_staking, provider_uri=MOCK_PROVIDER_URI) # Good selection mock_stdin.line(str(selection)) selected_account = select_client_account(emitter=test_emitter, network=TEMPORARY_DOMAIN, show_eth_balance=show_eth, show_nu_balance=show_tokens, show_staking=show_staking, provider_uri=MOCK_PROVIDER_URI) # check for accurate selection consistency with client index assert selected_account == mock_testerchain.client.accounts[selection] assert mock_stdin.empty() # Display account info headers = ['Account'] if show_staking: headers.append('Staking') if show_eth: headers.append('ETH') if show_tokens: headers.append('NU') captured = capsys.readouterr() for column_name in headers: assert column_name in captured.out, f'"{column_name}" column was not displayed' for account in mock_testerchain.client.accounts: assert account in captured.out if show_tokens: balance = mock_token_agent.get_balance(address=account) assert str(NU.from_nunits(balance)) in captured.out if show_eth: balance = mock_testerchain.client.get_balance(account=account) assert str(Web3.fromWei(balance, 'ether')) in captured.out if show_staking: if len(stake_info) == 0: assert "No" in captured.out else: assert 'Yes' in captured.out