def test_account_selection(click_runner, mocker, mock_testerchain,
                           mock_worklock_agent, test_registry_source_manager):
    accounts = list(mock_testerchain.client.accounts)
    index = random.choice(range(len(accounts)))
    the_chosen_one = accounts[index]

    # I spy
    mock_select = mocker.spy(worklock_command, 'select_client_account')

    command = ('cancel-bid', '--provider', MOCK_PROVIDER_URI, '--network',
               TEMPORARY_DOMAIN)

    user_input = '\n'.join((str(index), INSECURE_DEVELOPMENT_PASSWORD, YES))
    result = click_runner.invoke(worklock,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Check call
    mock_select.assert_called_once()

    # Check output
    assert GENERIC_SELECT_ACCOUNT in result.output
    assert SELECTED_ACCOUNT.format(
        choice=index, chosen_account=the_chosen_one) in result.output
    assert COLLECT_ETH_PASSWORD.format(
        checksum_address=the_chosen_one) in result.output
Beispiel #2
0
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:
            testnet = network != NetworksInventory.MAINNET
            signer = Signer.from_signer_uri(signer_uri, testnet=testnet)

        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.refresh_stakes()
            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
Beispiel #3
0
def select_client_account(emitter,
                          eth_provider_uri: str = None,
                          signer: Signer = None,
                          signer_uri: str = None,
                          prompt: str = None,
                          default: int = 0,
                          registry: BaseContractRegistry = 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 signer and signer_uri:
        raise ValueError('Pass either signer or signer_uri but not both.')

    if not any((eth_provider_uri, signer_uri, signer)):
        raise ValueError(
            "At least a provider URI, signer URI or signer must be provided to select an account"
        )

    if eth_provider_uri:
        # Connect to the blockchain in order to select an account
        if not BlockchainInterfaceFactory.is_interface_initialized(
                eth_provider_uri=eth_provider_uri):
            BlockchainInterfaceFactory.initialize_interface(
                eth_provider_uri=eth_provider_uri, poa=poa, emitter=emitter)
        if not signer_uri:
            signer_uri = eth_provider_uri

    blockchain = BlockchainInterfaceFactory.get_interface(
        eth_provider_uri=eth_provider_uri)

    if signer_uri and not signer:
        testnet = network != NetworksInventory.MAINNET
        signer = Signer.from_signer_uri(signer_uri, testnet=testnet)

    # 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)

    enumerated_accounts = dict(enumerate(signer.accounts))
    if len(enumerated_accounts) < 1:
        emitter.echo(NO_ETH_ACCOUNTS, color='red', bold=True)
        raise click.Abort()
    elif len(enumerated_accounts) == 1:
        # There are no choices if there is only one available address.
        return enumerated_accounts[0]

    # 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(domain=network,
                            checksum_address=account,
                            registry=registry)
            staker.refresh_stakes()
            is_staking = 'Yes' if bool(staker.stakes) else 'No'
            row.append(is_staking)
        if show_eth_balance:
            ether_balance = Web3.fromWei(
                blockchain.client.get_balance(account), 'ether')
            row.append(f'{ether_balance} ETH')
        if show_nu_balance:
            token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                                   registry=registry)
            token_balance = NU.from_units(
                token_agent.get_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