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