Example #1
0
def test_handle_selection_with_no_divisible_stakes(
        test_emitter,
        token_economics,
        mock_staking_agent,
        test_registry,
        mock_testerchain,
        mock_stdin,  # used to assert the user hasn't been prompted
        capsys,
        non_divisible_stakes):

    # Setup
    mock_staking_agent.get_all_stakes.return_value = non_divisible_stakes

    stakeholder = StakeHolder(registry=test_registry)
    stakeholder.assimilate(checksum_address=mock_testerchain.etherbase_account,
                           password=INSECURE_DEVELOPMENT_PASSWORD)

    # FAILURE: Divisible only with no divisible stakes on chain
    with pytest.raises(click.Abort):
        select_stake(emitter=test_emitter,
                     divisible=True,
                     stakeholder=stakeholder)

    # Divisible warning was displayed, but having
    # no divisible stakes cases an expected failure
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND not in captured.out
    assert ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE in captured.out
    assert_stake_table_not_painted(output=captured.out)
Example #2
0
def select_client_account_for_staking(
    emitter: StdoutEmitter,
    stakeholder: StakeHolder,
    staking_address: Optional[str],
) -> Tuple[str, str]:
    """
    Manages client account selection for stake-related operations.
    It always returns a tuple of addresses: the first is the local client account and the second is the staking address.

    When this is not a preallocation staker (which is the normal use case), both addresses are the same.
    Otherwise, when the staker is a contract managed by a beneficiary account,
    then the local client account is the beneficiary, and the staking address is the address of the staking contract.
    """

    if staking_address:
        client_account = staking_address
    else:
        client_account = select_client_account(
            prompt=SELECT_STAKING_ACCOUNT_INDEX,
            emitter=emitter,
            registry=stakeholder.registry,
            network=stakeholder.domain,
            signer=stakeholder.signer)
        staking_address = client_account
    stakeholder.assimilate(client_account)

    return client_account, staking_address
Example #3
0
def stakeholder_with_no_divisible_stakes(mock_testerchain, token_economics,
                                         mock_staking_agent, test_registry,
                                         non_divisible_stakes):
    mock_staking_agent.get_all_stakes.return_value = non_divisible_stakes
    stakeholder = StakeHolder(registry=test_registry)
    account = mock_testerchain.etherbase_account
    stakeholder.assimilate(checksum_address=account,
                           password=INSECURE_DEVELOPMENT_PASSWORD)
    return stakeholder
Example #4
0
def test_stakeholder_configuration(test_emitter, test_registry,
                                   mock_testerchain, mock_staking_agent):

    stakeholder_config_options = StakeHolderConfigOptions(
        provider_uri=MOCK_PROVIDER_URI,
        poa=None,
        light=None,
        registry_filepath=None,
        network=TEMPORARY_DOMAIN,
        signer_uri=None)

    mock_staking_agent.get_all_stakes.return_value = [SubStakeInfo(1, 2, 3)]
    force = False
    selected_index = 0
    selected_account = mock_testerchain.client.accounts[selected_index]
    expected_stakeholder = StakeHolder(registry=test_registry,
                                       domains={TEMPORARY_DOMAIN},
                                       initial_address=selected_account)
    expected_stakeholder.refresh_stakes()

    staker_options = StakerOptions(config_options=stakeholder_config_options,
                                   staking_address=selected_account)
    transacting_staker_options = TransactingStakerOptions(
        staker_options=staker_options,
        hw_wallet=None,
        beneficiary_address=None,
        allocation_filepath=None)
    stakeholder_from_configuration = transacting_staker_options.create_character(
        emitter=test_emitter, config_file=None)
    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder_from_configuration,
        staking_address=selected_account,
        individual_allocation=None,
        force=force)
    assert client_account == staking_address == selected_account
    assert stakeholder_from_configuration.stakes == expected_stakeholder.stakes
    assert stakeholder_from_configuration.checksum_address == client_account

    staker_options = StakerOptions(config_options=stakeholder_config_options,
                                   staking_address=None)
    transacting_staker_options = TransactingStakerOptions(
        staker_options=staker_options,
        hw_wallet=None,
        beneficiary_address=None,
        allocation_filepath=None)
    stakeholder_from_configuration = transacting_staker_options.create_character(
        emitter=None, config_file=None)
    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder_from_configuration,
        staking_address=selected_account,
        individual_allocation=None,
        force=force)
    assert client_account == staking_address == selected_account
    assert stakeholder_from_configuration.stakes == expected_stakeholder.stakes
    assert stakeholder_from_configuration.checksum_address == client_account
Example #5
0
def test_new_stakeholder(click_runner,
                         custom_filepath,
                         mock_registry_filepath,
                         testerchain):

    init_args = ('stake', 'new-stakeholder',
                 '--poa',
                 '--config-root', custom_filepath,
                 '--provider', TEST_PROVIDER_URI,
                 '--registry-filepath', mock_registry_filepath)

    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Files and Directories
    assert os.path.isdir(custom_filepath), 'Configuration file does not exist'

    custom_config_filepath = os.path.join(custom_filepath, StakeHolder.generate_filename())
    assert os.path.isfile(custom_config_filepath), 'Configuration file does not exist'

    with open(custom_config_filepath, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['blockchain']['provider_uri'] == TEST_PROVIDER_URI
Example #6
0
def select_stake(stakeholder: StakeHolder,
                 emitter: StdoutEmitter,
                 divisible: bool = False,
                 staker_address: str = None
                 ) -> Stake:
    """Interactively select a stake or abort if there are no eligible stakes."""

    # Precondition: Active Stakes
    if staker_address:
        staker = stakeholder.get_staker(checksum_address=staker_address)
        stakes = staker.stakes
    else:
        stakes = stakeholder.all_stakes
    if not stakes:
        emitter.echo(NO_STAKES_FOUND, color='red')
        raise click.Abort

    # Precondition: Divisible Stakes
    stakes = stakeholder.sorted_stakes
    if divisible:
        emitter.echo(ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE, color='yellow')
        stakes = stakeholder.divisible_stakes
        if not stakes:
            emitter.echo(NO_DIVISIBLE_STAKES, color='red')
            raise click.Abort

    # Interactive Selection
    enumerated_stakes = dict(enumerate(stakes))
    paint_stakes(stakeholder=stakeholder, emitter=emitter, staker_address=staker_address)
    choice = click.prompt(SELECT_STAKE, type=click.IntRange(min=0, max=len(enumerated_stakes)-1))
    chosen_stake = enumerated_stakes[choice]
    return chosen_stake
Example #7
0
def test_select_client_account_for_staking_cli_action(
        test_emitter, test_registry, test_registry_source_manager, mock_stdin,
        mock_testerchain, capsys, mocker, mock_staking_agent):
    """Fine-grained assertions about the return value of interactive client account selection"""
    force = False
    mock_staking_agent.get_all_stakes.return_value = []

    selected_index = 0
    selected_account = mock_testerchain.client.accounts[selected_index]

    stakeholder = StakeHolder(registry=test_registry,
                              domains={TEMPORARY_DOMAIN})

    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder,
        staking_address=selected_account,
        individual_allocation=None,
        force=force)
    assert client_account == staking_address == selected_account

    mock_stdin.line(str(selected_index))
    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder,
        staking_address=None,
        individual_allocation=None,
        force=force)
    assert client_account == staking_address == selected_account
    assert mock_stdin.empty()

    staking_contract_address = '0xFABADA'
    mock_individual_allocation = mocker.Mock(
        beneficiary_address=selected_account,
        contract_address=staking_contract_address)
    mock_stdin.line(YES)
    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder,
        individual_allocation=mock_individual_allocation,
        staking_address=None,
        force=force)

    assert client_account == selected_account
    assert staking_address == staking_contract_address
    assert mock_stdin.empty()

    captured = capsys.readouterr()
    message = PREALLOCATION_STAKE_ADVISORY.format(
        client_account=selected_account,
        staking_address=staking_contract_address)
    assert message in captured.out
Example #8
0
def software_stakeholder(testerchain, agency, stakeholder_config_file_location,
                         test_registry):
    token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                           registry=test_registry)

    # Setup
    path = stakeholder_config_file_location
    if path.exists():
        path.unlink()

    #                          0xaAa482c790b4301bE18D75A0D1B11B2ACBEF798B
    stakeholder_private_key = '255f64a948eeb1595b8a2d1e76740f4683eca1c8f1433d13293db9b6e27676cc'
    address = testerchain.provider.ethereum_tester.add_account(
        private_key=stakeholder_private_key,
        password=INSECURE_DEVELOPMENT_PASSWORD)

    testerchain.provider.ethereum_tester.unlock_account(
        account=address, password=INSECURE_DEVELOPMENT_PASSWORD)

    tx = {
        'to': address,
        'from': testerchain.etherbase_account,
        'value': Web3.toWei('1', 'ether')
    }

    txhash = testerchain.client.w3.eth.sendTransaction(tx)
    _receipt = testerchain.wait_for_receipt(txhash)

    # Mock TransactingPower consumption (Etherbase)
    transacting_power = TransactingPower(
        account=testerchain.etherbase_account,
        signer=Web3Signer(testerchain.client),
        password=INSECURE_DEVELOPMENT_PASSWORD)

    token_agent.transfer(amount=NU(200_000, 'NU').to_nunits(),
                         transacting_power=transacting_power,
                         target_address=address)

    # Create stakeholder from on-chain values given accounts over a web3 provider
    signer = Web3Signer(testerchain.client)
    signer.unlock_account(account=address,
                          password=INSECURE_DEVELOPMENT_PASSWORD)
    stakeholder = StakeHolder(registry=test_registry,
                              domain=TEMPORARY_DOMAIN,
                              signer=signer,
                              initial_address=address)

    # Teardown
    yield stakeholder
    if path.exists():
        path.unlink()
Example #9
0
def select_client_account_for_staking(
    emitter: StdoutEmitter,
    stakeholder: StakeHolder,
    staking_address: Optional[str],
    individual_allocation: Optional[IndividualAllocationRegistry],
    force: bool,
) -> Tuple[str, str]:
    """
    Manages client account selection for stake-related operations.
    It always returns a tuple of addresses: the first is the local client account and the second is the staking address.

    When this is not a preallocation staker (which is the normal use case), both addresses are the same.
    Otherwise, when the staker is a contract managed by a beneficiary account,
    then the local client account is the beneficiary, and the staking address is the address of the staking contract.
    """

    if individual_allocation:
        client_account = individual_allocation.beneficiary_address
        staking_address = individual_allocation.contract_address
        message = PREALLOCATION_STAKE_ADVISORY.format(
            client_account=client_account, staking_address=staking_address)
        emitter.echo(message, color='yellow', verbosity=1)
        if not force:
            click.confirm(IS_THIS_CORRECT, abort=True)
    else:
        if staking_address:
            client_account = staking_address
        else:
            client_account = select_client_account(
                prompt=SELECT_STAKING_ACCOUNT_INDEX,
                emitter=emitter,
                registry=stakeholder.registry,
                network=stakeholder.network,
                wallet=stakeholder.wallet)
            staking_address = client_account
    stakeholder.set_staker(client_account)

    return client_account, staking_address
Example #10
0
def stakeholder(current_period, mock_staking_agent, test_registry):
    mock_staking_agent.get_current_period.return_value = current_period

    staker_info = StakerInfo(current_committed_period=current_period - 1,
                             next_committed_period=current_period,
                             value=0,
                             last_committed_period=0,
                             lock_restake_until_period=False,
                             completed_work=0,
                             worker_start_period=0,
                             worker=NULL_ADDRESS,
                             flags=bytes())
    mock_staking_agent.get_staker_info.return_value = staker_info

    return StakeHolder(registry=test_registry)
Example #11
0
def software_stakeholder(testerchain, agency,
                         stakeholder_config_file_location):

    # Setup
    path = stakeholder_config_file_location
    if os.path.exists(path):
        os.remove(path)

    #                          0xaAa482c790b4301bE18D75A0D1B11B2ACBEF798B
    stakeholder_private_key = '255f64a948eeb1595b8a2d1e76740f4683eca1c8f1433d13293db9b6e27676cc'
    address = testerchain.provider.ethereum_tester.add_account(
        stakeholder_private_key, password=INSECURE_DEVELOPMENT_PASSWORD)

    testerchain.provider.ethereum_tester.unlock_account(
        address, password=INSECURE_DEVELOPMENT_PASSWORD)

    tx = {
        'to': address,
        'from': testerchain.etherbase_account,
        'value': Web3.toWei('1', 'ether')
    }

    txhash = testerchain.client.w3.eth.sendTransaction(tx)
    _receipt = testerchain.wait_for_receipt(txhash)

    # Mock TransactingPower consumption (Etherbase)
    transacting_power = TransactingPower(
        account=testerchain.etherbase_account,
        password=INSECURE_DEVELOPMENT_PASSWORD,
        blockchain=testerchain)
    transacting_power.activate()

    token_agent = Agency.get_agent(NucypherTokenAgent)
    token_agent.transfer(amount=NU(200_000, 'NU').to_nunits(),
                         sender_address=testerchain.etherbase_account,
                         target_address=address)

    # Create stakeholder from on-chain values given accounts over a web3 provider
    stakeholder = StakeHolder(blockchain=testerchain,
                              funding_account=address,
                              funding_password=INSECURE_DEVELOPMENT_PASSWORD,
                              trezor=False)

    # Teardown
    yield stakeholder
    if os.path.exists(path):
        os.remove(path)
def stakeholder(current_period, mock_staking_agent, test_registry, mock_testerchain):
    mock_staking_agent.get_current_period.return_value = current_period

    staker_info = StakerInfo(current_committed_period=current_period-1,
                             next_committed_period=current_period,
                             value=0,
                             last_committed_period=0,
                             lock_restake_until_period=False,
                             completed_work=0,
                             worker_start_period=0,
                             worker=NULL_ADDRESS,
                             flags=bytes())
    mock_staking_agent.get_staker_info.return_value = staker_info

    return StakeHolder(registry=test_registry,
                       domain=TEMPORARY_DOMAIN,
                       signer=Web3Signer(mock_testerchain.client))
Example #13
0
def test_handle_select_stake_with_no_stakes(
        test_emitter,
        token_economics,
        mock_staking_agent,
        test_registry,
        mock_testerchain,
        mock_stdin,  # used to assert user hasn't been prompted
        capsys):

    # Setup
    mock_stakes = []
    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    stakeholder = StakeHolder(registry=test_registry)

    # Test
    with pytest.raises(click.Abort):
        select_stake(emitter=test_emitter, stakeholder=stakeholder)

    # Examine
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND in captured.out
    assert_stake_table_not_painted(output=captured.out)
Example #14
0
def test_software_stakeholder_configuration(testerchain, software_stakeholder,
                                            stakeholder_config_file_location):

    stakeholder = software_stakeholder
    path = stakeholder_config_file_location

    # Check attributes can be successfully read
    assert stakeholder.total_stake == 0
    assert not stakeholder.stakes
    assert stakeholder.accounts

    # Save the stakeholder JSON config
    stakeholder.to_configuration_file(filepath=path)
    with open(stakeholder.filepath, 'r') as file:

        # Ensure file contents are serializable
        contents = file.read()
        first_config_contents = json.loads(contents)

    # Destroy this stake holder, leaving only the configuration file behind
    del stakeholder

    # Restore StakeHolder instance from JSON config
    the_same_stakeholder = StakeHolder.from_configuration_file(
        filepath=path,
        funding_password=INSECURE_DEVELOPMENT_PASSWORD,
        blockchain=testerchain)

    # Save the JSON config again
    the_same_stakeholder.to_configuration_file(filepath=path, override=True)
    with open(the_same_stakeholder.filepath, 'r') as file:
        contents = file.read()
        second_config_contents = json.loads(contents)

    # Ensure the stakeholder was accurately restored from JSON config
    assert first_config_contents == second_config_contents
def test_select_client_account_for_staking_cli_action(
        test_emitter, test_registry, test_registry_source_manager, mock_stdin,
        mock_testerchain, capsys, mock_staking_agent):
    """Fine-grained assertions about the return value of interactive client account selection"""
    mock_staking_agent.get_all_stakes.return_value = []

    selected_index = 0
    selected_account = mock_testerchain.client.accounts[selected_index]

    stakeholder = StakeHolder(registry=test_registry,
                              domain=TEMPORARY_DOMAIN,
                              signer=Web3Signer(mock_testerchain.client))

    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter,
        stakeholder=stakeholder,
        staking_address=selected_account)
    assert client_account == staking_address == selected_account

    mock_stdin.line(str(selected_index))
    client_account, staking_address = select_client_account_for_staking(
        emitter=test_emitter, stakeholder=stakeholder, staking_address=None)
    assert client_account == staking_address == selected_account
    assert mock_stdin.empty()
Example #16
0
def stake(
    click_config,
    action,
    config_root,
    config_file,

    # Mode
    force,
    offline,
    hw_wallet,

    # Blockchain
    poa,
    registry_filepath,
    provider_uri,
    sync,

    # Stake
    staking_address,
    worker_address,
    withdraw_address,
    value,
    duration,
    index,
    policy_reward,
    staking_reward,
) -> None:
    """
    Manage stakes and other staker-related operations.

    \b
    Actions
    -------------------------------------------------
    new-stakeholder  Create a new stakeholder configuration
    list             List active stakes for current stakeholder
    accounts         Show ETH and NU balances for stakeholder's accounts
    sync             Synchronize stake data with on-chain information
    set-worker       Bound a worker to a staker
    detach-worker    Detach worker currently bound to a staker
    init             Create a new stake
    divide           Create a new stake from part of an existing one
    collect-reward   Withdraw staking reward

    """

    # Banner
    emitter = click_config.emitter
    emitter.clear()
    emitter.banner(NU_BANNER)

    if action == 'new-stakeholder':

        if not provider_uri:
            raise click.BadOptionUsage(
                option_name='--provider',
                message="--provider is required to create a new stakeholder.")

        registry = None
        fetch_registry = True
        if registry_filepath:
            registry = EthereumContractRegistry(
                registry_filepath=registry_filepath)
            fetch_registry = False
        blockchain = BlockchainInterface(provider_uri=provider_uri,
                                         registry=registry,
                                         poa=poa)
        blockchain.connect(sync_now=sync, fetch_registry=fetch_registry)

        new_stakeholder = StakeHolder(config_root=config_root,
                                      offline_mode=offline,
                                      blockchain=blockchain)

        filepath = new_stakeholder.to_configuration_file(override=force)
        emitter.echo(f"Wrote new stakeholder configuration to {filepath}",
                     color='green')
        return  # Exit

    #
    # Make Staker
    #

    STAKEHOLDER = StakeHolder.from_configuration_file(
        filepath=config_file,
        provider_uri=provider_uri,
        registry_filepath=registry_filepath,
        offline=offline,
        sync_now=sync)
    #
    # Eager Actions
    #

    if action == 'list':
        if not STAKEHOLDER.stakes:
            emitter.echo(f"There are no active stakes")
        else:
            painting.paint_stakes(emitter=emitter, stakes=STAKEHOLDER.stakes)
        return

    elif action == 'accounts':
        for address, balances in STAKEHOLDER.account_balances.items():
            emitter.echo(
                f"{address} | {Web3.fromWei(balances['ETH'], 'ether')} ETH | {NU.from_nunits(balances['NU'])}"
            )
        return  # Exit

    elif action == 'sync':
        emitter.echo("Reading on-chain stake data...")
        STAKEHOLDER.read_onchain_stakes()
        STAKEHOLDER.to_configuration_file(override=True)
        emitter.echo("OK!", color='green')
        return  # Exit

    elif action in ('set-worker', 'detach-worker'):

        if not staking_address:
            staking_address = select_stake(stakeholder=STAKEHOLDER,
                                           emitter=emitter).owner_address

        if action == 'set-worker':
            if not worker_address:
                worker_address = click.prompt("Enter worker address",
                                              type=EIP55_CHECKSUM_ADDRESS)
        elif action == 'detach-worker':
            if worker_address:
                raise click.BadOptionUsage(
                    message=
                    "detach-worker cannot be used together with --worker-address option"
                )
            worker_address = BlockchainInterface.NULL_ADDRESS

        password = None
        if not hw_wallet and not STAKEHOLDER.blockchain.client.is_local:
            password = get_client_password(checksum_address=staking_address)
        receipt = STAKEHOLDER.set_worker(staker_address=staking_address,
                                         password=password,
                                         worker_address=worker_address)

        emitter.echo(f"OK | Receipt: {receipt['transactionHash'].hex()}",
                     color='green')
        return  # Exit

    elif action == 'init':
        """Initialize a new stake"""

        #
        # Get Staking Account
        #

        password = None
        if not staking_address:
            staking_address = select_client_account(
                blockchain=STAKEHOLDER.blockchain,
                prompt="Select staking account",
                emitter=emitter)

        if not hw_wallet and not STAKEHOLDER.blockchain.client.is_local:
            password = click.prompt(
                f"Enter password to unlock {staking_address}",
                hide_input=True,
                confirmation_prompt=False)
        #
        # Stage Stake
        #

        if not value:
            min_locked = STAKEHOLDER.economics.minimum_allowed_locked
            value = click.prompt(
                f"Enter stake value in NU",
                type=STAKE_VALUE,
                default=NU.from_nunits(min_locked).to_tokens())
        value = NU.from_tokens(value)

        if not duration:
            prompt = f"Enter stake duration ({STAKEHOLDER.economics.minimum_locked_periods} periods minimum)"
            duration = click.prompt(prompt, type=STAKE_DURATION)

        start_period = STAKEHOLDER.staking_agent.get_current_period()
        end_period = start_period + duration

        #
        # Review
        #

        if not force:
            painting.paint_staged_stake(emitter=emitter,
                                        stakeholder=STAKEHOLDER,
                                        staking_address=staking_address,
                                        stake_value=value,
                                        duration=duration,
                                        start_period=start_period,
                                        end_period=end_period)

            confirm_staged_stake(staker_address=staking_address,
                                 value=value,
                                 duration=duration)

        # Last chance to bail
        click.confirm("Publish staged stake to the blockchain?", abort=True)

        # Execute
        new_stake = STAKEHOLDER.initialize_stake(
            amount=value,
            duration=duration,
            checksum_address=staking_address,
            password=password)

        painting.paint_staking_confirmation(
            emitter=emitter,
            ursula=STAKEHOLDER,
            transactions=new_stake.transactions)
        return  # Exit

    elif action == 'divide':
        """Divide an existing stake by specifying the new target value and end period"""

        if staking_address and index is not None:
            staker = STAKEHOLDER.get_active_staker(address=staking_address)
            current_stake = staker.stakes[index]
        else:
            current_stake = select_stake(stakeholder=STAKEHOLDER,
                                         emitter=emitter)

        #
        # Stage Stake
        #

        # Value
        if not value:
            value = click.prompt(
                f"Enter target value (must be less than or equal to {str(current_stake.value)})",
                type=STAKE_VALUE)
        value = NU(value, 'NU')

        # Duration
        if not duration:
            extension = click.prompt("Enter number of periods to extend",
                                     type=STAKE_EXTENSION)
        else:
            extension = duration

        if not force:
            painting.paint_staged_stake_division(emitter=emitter,
                                                 stakeholder=STAKEHOLDER,
                                                 original_stake=current_stake,
                                                 target_value=value,
                                                 extension=extension)
            click.confirm("Is this correct?", abort=True)

        # Execute
        password = None
        if not hw_wallet and not STAKEHOLDER.blockchain.client.is_local:
            password = get_client_password(
                checksum_address=current_stake.owner_address)
        modified_stake, new_stake = STAKEHOLDER.divide_stake(
            address=current_stake.owner_address,
            index=current_stake.index,
            value=value,
            duration=extension,
            password=password)
        emitter.echo('Successfully divided stake', color='green', verbosity=1)
        emitter.echo(f'Receipt ........... {new_stake.receipt}', verbosity=1)

        # Show the resulting stake list
        painting.paint_stakes(emitter=emitter, stakes=STAKEHOLDER.stakes)
        return  # Exit

    elif action == 'collect-reward':
        """Withdraw staking reward to the specified wallet address"""
        password = None
        if not hw_wallet and not STAKEHOLDER.blockchain.client.is_local:
            password = get_client_password(checksum_address=staking_address)
        STAKEHOLDER.collect_rewards(staker_address=staking_address,
                                    withdraw_address=withdraw_address,
                                    password=password,
                                    staking=staking_reward,
                                    policy=policy_reward)

    else:
        ctx = click.get_current_context()
        click.UsageError(message=f"Unknown action '{action}'.", ctx=ctx).show()
    return  # Exit
def stakeholder_configuration_file_location(custom_filepath):
    _configuration_file_location = os.path.join(
        MOCK_CUSTOM_INSTALLATION_PATH, StakeHolder.generate_filename())
    return _configuration_file_location