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
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
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')
Exemplo n.º 5
0
 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)
Exemplo n.º 7
0
 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())
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
    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,
        )
Exemplo n.º 13
0
    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,
        )
Exemplo n.º 14
0
    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)
Exemplo n.º 15
0
    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)
Exemplo n.º 16
0
    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)
Exemplo n.º 17
0
    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)
Exemplo n.º 18
0
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)
Exemplo n.º 19
0
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
Exemplo n.º 20
0
    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