Пример #1
0
def test_handle_selection_with_with_no_editable_stakes(
        test_emitter,
        stakeholder,
        mock_staking_agent,
        mock_testerchain,
        mock_stdin,  # used to assert user hasn't been prompted
        capsys,
        current_period,
        token_economics,
        sub_stakes_functions):
    mock_stakes = make_sub_stakes(current_period, token_economics,
                                  sub_stakes_functions)

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.set_staker(staker)

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

    # Examine
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND in captured.out
    assert_stake_table_not_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #2
0
def test_handle_selection_with_no_divisible_stakes(
        test_emitter,
        stakeholder,
        mock_staking_agent,
        mock_testerchain,
        mock_stdin,  # used to assert user hasn't been prompted
        capsys,
        current_period,
        token_economics):

    # Setup
    mock_stakes = make_sub_stakes(current_period, token_economics,
                                  [non_divisible_sub_stakes])

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.set_staker(staker)

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

    # Divisible warning was displayed, but having
    # no divisible stakes cases an expected failure
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND in captured.out
    assert ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE in captured.out
    assert_stake_table_not_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #3
0
def test_no_stakes_with_filter_function(test_emitter,
                                        stakeholder,
                                        mock_staking_agent,
                                        mock_testerchain,
                                        mock_stdin,  # used to assert user hasn't been prompted
                                        capsys,
                                        current_period,
                                        token_economics,
                                        sub_stakes_functions):
    # Setup
    mock_stakes = make_sub_stakes(current_period, token_economics, sub_stakes_functions)

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.assimilate(staker, password=INSECURE_DEVELOPMENT_PASSWORD)

    # FAILURE: no stakes with specified final period
    with pytest.raises(click.Abort):
        select_stake(emitter=test_emitter,
                     staker=stakeholder.staker,
                     stakes_status=Stake.Status.LOCKED,
                     filter_function=lambda stake: stake.final_locked_period == current_period)

    # Divisible warning was displayed, but having
    # no divisible stakes causes an expected failure
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND in captured.out
    assert_stake_table_not_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #4
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)
Пример #5
0
def merge(general_config, transacting_staker_options, config_file, force, index_1, index_2):
    """Merge two stakes into one."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
    action_period = STAKEHOLDER.staking_agent.get_current_period()
    blockchain = transacting_staker_options.get_blockchain()

    client_account, staking_address = select_client_account_for_staking(
        emitter=emitter,
        stakeholder=STAKEHOLDER,
        staking_address=transacting_staker_options.staker_options.staking_address,
        individual_allocation=STAKEHOLDER.individual_allocation,
        force=force)

    # Handle stakes selection
    stake_1, stake_2 = None, None

    if index_1 is not None and index_2 is not None:
        stake_1 = STAKEHOLDER.stakes[index_1]
        stake_2 = STAKEHOLDER.stakes[index_2]
    elif index_1 is not None:  # 0 is valid.
        stake_1 = STAKEHOLDER.stakes[index_1]
    elif index_2 is not None:
        stake_1 = STAKEHOLDER.stakes[index_2]

    if stake_1 is None:
        stake_1 = select_stake(staker=STAKEHOLDER, emitter=emitter)
    if stake_2 is None:
        emitter.echo(ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE.format(final_period=stake_1.final_locked_period),
                     color='yellow')
        stake_2 = select_stake(staker=STAKEHOLDER,
                               emitter=emitter,
                               filter_function=lambda s: s.index != stake_1.index and
                                                         s.final_locked_period == stake_1.final_locked_period)

    if not force:
        click.confirm(CONFIRM_MERGE.format(stake_index_1=stake_1.index, stake_index_2=stake_2.index), abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)

    # Non-interactive: Consistency check to prevent the above agreement from going stale.
    last_second_current_period = STAKEHOLDER.staking_agent.get_current_period()
    if action_period != last_second_current_period:
        emitter.echo(PERIOD_ADVANCED_WARNING, color='red')
        raise click.Abort

    # Execute
    receipt = STAKEHOLDER.merge_stakes(stake_1=stake_1, stake_2=stake_2)

    # Report
    emitter.echo(SUCCESSFUL_STAKES_MERGE, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
    paint_stakes(emitter=emitter, staker=STAKEHOLDER)
Пример #6
0
def test_select_divisible_stake(test_emitter, token_economics,
                                mock_staking_agent, test_registry,
                                mock_testerchain, mock_stdin, capsys,
                                divisible_stakes,
                                stakeholder_with_divisible_stakes):

    expected_stake = Stake.from_stake_info(
        stake_info=divisible_stakes[0],
        staking_agent=mock_staking_agent,  # stakinator
        index=0,
        checksum_address=stakeholder_with_divisible_stakes.checksum_address,
        economics=token_economics)

    # SUCCESS: Display all divisible-only stakes and make a selection
    mock_stdin.line(str(SELECTION))

    selected_stake = select_stake(
        emitter=test_emitter,
        divisible=True,
        stakeholder=stakeholder_with_divisible_stakes)

    assert isinstance(selected_stake, Stake)
    assert selected_stake == expected_stake

    # Examine the output
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND not in captured.out
    assert ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE in captured.out
    assert_stake_table_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #7
0
def prolong(general_config, transacting_staker_options, config_file, force, lock_periods, index):
    """Prolong an existing stake's duration."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
    action_period = STAKEHOLDER.staking_agent.get_current_period()
    blockchain = transacting_staker_options.get_blockchain()
    economics = STAKEHOLDER.economics

    # Handle account selection
    client_account, staking_address = select_client_account_for_staking(
        emitter=emitter,
        stakeholder=STAKEHOLDER,
        staking_address=transacting_staker_options.staker_options.staking_address,
        individual_allocation=STAKEHOLDER.individual_allocation,
        force=force)

    # Handle stake update and selection
    if index is not None:  # 0 is valid.
        current_stake = STAKEHOLDER.stakes[index]
    else:
        current_stake = select_stake(staker=STAKEHOLDER, emitter=emitter)

    #
    # Prolong
    #

    # Interactive
    if not lock_periods:
        max_extension = MAX_UINT16 - current_stake.final_locked_period
        # +1 because current period excluded
        min_extension = economics.minimum_locked_periods - current_stake.periods_remaining + 1
        if min_extension < 1:
            min_extension = 1
        duration_extension_range = click.IntRange(min=min_extension, max=max_extension, clamp=False)
        lock_periods = click.prompt(PROMPT_PROLONG_VALUE.format(minimum=min_extension, maximum=max_extension),
                                    type=duration_extension_range)
    if not force:
        click.confirm(CONFIRM_PROLONG.format(lock_periods=lock_periods), abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)

    # Non-interactive: Consistency check to prevent the above agreement from going stale.
    last_second_current_period = STAKEHOLDER.staking_agent.get_current_period()
    if action_period != last_second_current_period:
        emitter.echo(PERIOD_ADVANCED_WARNING, color='red')
        raise click.Abort

    # Execute
    receipt = STAKEHOLDER.prolong_stake(stake=current_stake, additional_periods=lock_periods)

    # Report
    emitter.echo(SUCCESSFUL_STAKE_PROLONG, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
    paint_stakes(emitter=emitter, staker=STAKEHOLDER)
Пример #8
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)
Пример #9
0
def test_select_using_filter_function(
        test_emitter,
        stakeholder,
        mock_staking_agent,
        mock_testerchain,
        mock_stdin,  # used to assert user hasn't been prompted
        capsys,
        current_period,
        token_economics,
        sub_stakes_functions):
    # Setup
    mock_stakes = make_sub_stakes(current_period, token_economics,
                                  sub_stakes_functions)

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.set_staker(staker)

    selection = len(mock_stakes) - 1
    expected_stake = Stake.from_stake_info(
        stake_info=mock_stakes[selection],
        staking_agent=mock_staking_agent,  # stakinator
        index=selection,
        checksum_address=stakeholder.checksum_address,
        economics=token_economics)

    # SUCCESS: Display all editable-only stakes with specified final period
    mock_stdin.line(str(selection))
    selected_stake = select_stake(emitter=test_emitter,
                                  staker=stakeholder,
                                  stakes_status=Stake.Status.LOCKED,
                                  filter_function=lambda stake: stake.
                                  final_locked_period == current_period)

    assert isinstance(selected_stake, Stake)
    assert selected_stake == expected_stake

    # Examine the output
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND not in captured.out
    assert_stake_table_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #10
0
def test_select_divisible_stake(
        test_emitter,
        stakeholder,
        mock_staking_agent,
        mock_testerchain,
        mock_stdin,  # used to assert user hasn't been prompted
        capsys,
        current_period,
        token_economics,
        sub_stakes_functions):
    # Setup
    mock_stakes = make_sub_stakes(current_period, token_economics,
                                  sub_stakes_functions)

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.set_staker(staker)

    selection = len(mock_stakes) - 1
    expected_stake = Stake.from_stake_info(
        stake_info=mock_stakes[selection],
        staking_agent=mock_staking_agent,  # stakinator
        index=selection,
        checksum_address=stakeholder.checksum_address,
        economics=token_economics)

    # SUCCESS: Display all divisible-only stakes and make a selection
    mock_stdin.line(str(selection))
    selected_stake = select_stake(emitter=test_emitter,
                                  staker=stakeholder,
                                  stakes_status=Stake.Status.DIVISIBLE)

    assert isinstance(selected_stake, Stake)
    assert selected_stake == expected_stake

    # Examine the output
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND not in captured.out
    assert ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE in captured.out
    assert_stake_table_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #11
0
def test_select_editable_stake(test_emitter,
                               stakeholder,
                               mock_staking_agent,
                               mock_testerchain,
                               mock_stdin,  # used to assert user hasn't been prompted
                               capsys,
                               current_period,
                               token_economics,
                               sub_stakes_functions):
    mock_stakes = make_sub_stakes(current_period, token_economics, sub_stakes_functions)

    mock_staking_agent.get_all_stakes.return_value = mock_stakes
    staker = mock_testerchain.unassigned_accounts[0]
    stakeholder.assimilate(staker, password=INSECURE_DEVELOPMENT_PASSWORD)

    selection = len(mock_stakes) - 1
    expected_stake = Stake.from_stake_info(stake_info=mock_stakes[selection],
                                           staking_agent=mock_staking_agent,   # stakinator
                                           index=selection,
                                           checksum_address=stakeholder.checksum_address,
                                           economics=token_economics)

    # User's selection
    mock_stdin.line(str(selection))
    selected_stake = select_stake(emitter=test_emitter, staker=stakeholder.staker)

    # Check stake accuracy
    assert isinstance(selected_stake, Stake)
    assert selected_stake == expected_stake

    # Examine the output
    captured = capsys.readouterr()
    assert NO_STAKES_FOUND not in captured.out
    assert ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE not in captured.out
    assert_stake_table_painted(output=captured.out)
    assert mock_stdin.empty()
Пример #12
0
def divide(general_config, transacting_staker_options, config_file, force,
           value, lock_periods, index):
    """Create a new stake from part of an existing one."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()
    economics = STAKEHOLDER.economics
    action_period = STAKEHOLDER.staking_agent.get_current_period()

    client_account, staking_address = select_client_account_for_staking(
        emitter=emitter,
        stakeholder=STAKEHOLDER,
        staking_address=transacting_staker_options.staker_options.
        staking_address,
        individual_allocation=STAKEHOLDER.individual_allocation,
        force=force)

    # Dynamic click types (Economics)
    min_locked = economics.minimum_allowed_locked
    stake_value_range = click.FloatRange(
        min=NU.from_nunits(min_locked).to_tokens(), clamp=False)

    if transacting_staker_options.staker_options.staking_address and index is not None:  # 0 is valid.
        STAKEHOLDER.stakes = StakeList(
            registry=STAKEHOLDER.registry,
            checksum_address=transacting_staker_options.staker_options.
            staking_address)
        STAKEHOLDER.stakes.refresh()
        current_stake = STAKEHOLDER.stakes[index]
    else:
        current_stake = select_stake(stakeholder=STAKEHOLDER,
                                     emitter=emitter,
                                     divisible=True,
                                     staker_address=client_account)

    #
    # Stage Stake
    #

    # Value
    if not value:
        min_allowed_locked = NU.from_nunits(
            STAKEHOLDER.economics.minimum_allowed_locked)
        max_divide_value = max(min_allowed_locked,
                               current_stake.value - min_allowed_locked)
        prompt = PROMPT_STAKE_DIVIDE_VALUE.format(
            minimm=min_allowed_locked, maximum=str(max_divide_value))
        value = click.prompt(prompt, type=stake_value_range)
    value = NU(value, 'NU')

    # Duration
    if not lock_periods:
        max_extension = MAX_UINT16 - current_stake.final_locked_period
        divide_extension_range = click.IntRange(min=1,
                                                max=max_extension,
                                                clamp=False)
        extension = click.prompt(PROMPT_STAKE_EXTEND_VALUE,
                                 type=divide_extension_range)
    else:
        extension = lock_periods

    if not force:
        confirm_large_stake(lock_periods=extension, value=value)
        paint_staged_stake_division(emitter=emitter,
                                    stakeholder=STAKEHOLDER,
                                    original_stake=current_stake,
                                    target_value=value,
                                    extension=extension)
        click.confirm(CONFIRM_BROADCAST_STAKE_DIVIDE, abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)

    # Consistency check to prevent the above agreement from going stale.
    last_second_current_period = STAKEHOLDER.staking_agent.get_current_period()
    if action_period != last_second_current_period:
        emitter.echo(PERIOD_ADVANCED_WARNING, red='red')
        raise click.Abort

    # Execute
    STAKEHOLDER.assimilate(checksum_address=current_stake.staker_address,
                           password=password)
    modified_stake, new_stake = STAKEHOLDER.divide_stake(
        stake_index=current_stake.index,
        target_value=value,
        additional_periods=extension)
    emitter.echo(SUCCESSFUL_STAKE_DIVIDE, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter,
                          receipt=new_stake.receipt,
                          chain_name=blockchain.client.chain_name)

    # Show the resulting stake list
    paint_stakes(emitter=emitter, stakeholder=STAKEHOLDER)
Пример #13
0
def increase(general_config, transacting_staker_options, config_file, force, value, index, only_lock):
    """Increase an existing stake."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()

    client_account, staking_address = select_client_account_for_staking(
        emitter=emitter,
        stakeholder=STAKEHOLDER,
        staking_address=transacting_staker_options.staker_options.staking_address,
        individual_allocation=STAKEHOLDER.individual_allocation,
        force=force)

    # Handle stake update and selection
    if index is not None:  # 0 is valid.
        current_stake = STAKEHOLDER.stakes[index]
    else:
        current_stake = select_stake(staker=STAKEHOLDER, emitter=emitter)

    #
    # Stage Stake
    #

    if not value:
        if not only_lock:
            only_lock = not click.prompt(PROMPT_DEPOSIT_OR_LOCK, type=click.BOOL, default=True)

        token_balance = STAKEHOLDER.token_balance if not only_lock else STAKEHOLDER.calculate_staking_reward()
        locked_tokens = STAKEHOLDER.locked_tokens(periods=1).to_nunits()
        upper_limit = min(token_balance, NU.from_nunits(STAKEHOLDER.economics.maximum_allowed_locked - locked_tokens))

        if token_balance == 0:
            emitter.echo(INSUFFICIENT_BALANCE_TO_INCREASE, color='red')
            raise click.Abort
        if upper_limit == 0:
            emitter.echo(MAXIMUM_STAKE_REACHED, color='red')
            raise click.Abort

        stake_value_range = click.FloatRange(min=0, max=upper_limit.to_tokens(), clamp=False)
        value = click.prompt(PROMPT_STAKE_INCREASE_VALUE.format(upper_limit=upper_limit),
                             type=stake_value_range)
    value = NU.from_tokens(value)

    #
    # Review and Publish
    #

    if not force:
        lock_periods = current_stake.periods_remaining - 1
        current_period = STAKEHOLDER.staking_agent.get_current_period()
        unlock_period = current_stake.final_locked_period + 1

        confirm_large_stake(value=value, lock_periods=lock_periods)
        paint_staged_stake(emitter=emitter,
                           stakeholder=STAKEHOLDER,
                           staking_address=staking_address,
                           stake_value=value,
                           lock_periods=lock_periods,
                           start_period=current_period + 1,
                           unlock_period=unlock_period)
        click.confirm(CONFIRM_INCREASING_STAKE.format(stake_index=current_stake.index, value=value), abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)

    # Execute
    receipt = STAKEHOLDER.increase_stake(stake=current_stake, amount=value, only_lock=only_lock)

    # Report
    emitter.echo(SUCCESSFUL_STAKE_INCREASE, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
    paint_stakes(emitter=emitter, staker=STAKEHOLDER)