Merge pull request #2441 from cygnusv/floater

Allow arbitrary decimal precision as input to nucypher CLI
pull/2452/head
K Prasch 2020-12-01 09:58:35 -08:00 committed by GitHub
commit 5873dc4fb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 38 deletions

View File

@ -0,0 +1 @@
Allow arbitrary decimal precision when entering NU amounts to nucypher CLI.

View File

@ -48,21 +48,24 @@ class NU:
An amount of NuCypher tokens that doesn't hurt your eyes.
Wraps the eth_utils currency conversion methods.
The easiest way to use NU, is to pass an int, float, or str, and denomination string:
The easiest way to use NU, is to pass an int, Decimal, or str, and denomination string:
Int: nu = NU(100, 'NU')
Int: nu_wei = NU(15000000000000000000000, 'NuNit')
Int: nu = NU(15000000000000000000000, 'NuNit')
Float: nu = NU(15042.445, 'NU')
Decimal: nu = NU(Decimal('15042.445'), 'NU')
String: nu = NU('10002.302', 'NU')
...or alternately...
Float: nu = NU.from_tokens(100.50)
Int: nu_wei = NU.from_nu_wei(15000000000000000000000)
Decimal: nu = NU.from_tokens(Decimal('100.50'))
Int: nu = NU.from_nunits(15000000000000000000000)
Token quantity is stored internally as an int in the smallest denomination,
and all arithmetic operations use this value.
Using float inputs to this class to represent amounts of NU is supported but not recommended,
as floats don't have enough precision to represent some quantities.
"""
__symbol = 'NU'
@ -74,7 +77,7 @@ class NU:
class InvalidDenomination(ValueError):
"""Raised when an unknown denomination string is passed into __init__"""
def __init__(self, value: Union[int, float, str], denomination: str):
def __init__(self, value: Union[int, Decimal, str], denomination: str):
# Lookup Conversion
try:
@ -97,7 +100,7 @@ class NU:
return cls(value, denomination='NuNit')
@classmethod
def from_tokens(cls, value: Union[int, float, str]) -> 'NU':
def from_tokens(cls, value: Union[int, Decimal, str]) -> 'NU':
return cls(value, denomination='NU')
def to_tokens(self) -> Decimal:

View File

@ -107,7 +107,7 @@ from nucypher.cli.utils import setup_emitter
from nucypher.config.characters import StakeHolderConfiguration
from nucypher.utilities.gas_strategies import construct_fixed_price_gas_strategy
option_value = click.option('--value', help="Token value of stake", type=click.INT)
option_value = click.option('--value', help="Token value of stake", type=DecimalRange(min=0))
option_lock_periods = click.option('--lock-periods', help="Duration of stake in periods.", type=click.INT)
option_worker_address = click.option('--worker-address', help="Address to bond as an Ursula-Worker", type=EIP55_CHECKSUM_ADDRESS)
option_index = click.option('--index', help="The staker-specific stake index to edit", type=click.INT)
@ -498,7 +498,7 @@ def create(general_config: GroupGeneralConfig,
# 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)
stake_value_range = DecimalRange(min=NU.from_nunits(min_locked).to_tokens(), clamp=False)
stake_duration_range = click.IntRange(min=economics.minimum_locked_periods, clamp=False)
#
@ -625,7 +625,7 @@ def increase(general_config: GroupGeneralConfig,
emitter.echo(MAXIMUM_STAKE_REACHED, color='red')
raise click.Abort
stake_value_range = click.FloatRange(min=0, max=upper_limit.to_tokens(), clamp=False)
stake_value_range = DecimalRange(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)
@ -872,7 +872,7 @@ def divide(general_config: GroupGeneralConfig,
# 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)
stake_value_range = DecimalRange(min=NU.from_nunits(min_locked).to_tokens(), clamp=False)
if index is not None: # 0 is valid.
current_stake = STAKEHOLDER.stakes[index]

View File

@ -341,9 +341,9 @@ def test_nothing_to_mint(click_runner, surrogate_stakers, mock_staking_agent, mo
mock_staking_agent.get_next_committed_period.return_value = 0
mint_command = ('mint',
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
user_input = INSECURE_DEVELOPMENT_PASSWORD
result = click_runner.invoke(stake, mint_command, input=user_input, catch_exceptions=False)
@ -367,9 +367,9 @@ def test_mint_with_warning(click_runner, surrogate_stakers, mock_staking_agent,
mock_staking_agent.non_withdrawable_stake.return_value = NU(1, 'NU').to_nunits()
mint_command = ('mint',
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
user_input = '\n'.join((INSECURE_DEVELOPMENT_PASSWORD, YES))
result = click_runner.invoke(stake, mint_command, input=user_input, catch_exceptions=False)
@ -394,9 +394,9 @@ def test_mint_without_warning(click_runner, surrogate_stakers, mock_staking_agen
mock_staking_agent.non_withdrawable_stake.return_value = 0
mint_command = ('mint',
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0])
user_input = '\n'.join((INSECURE_DEVELOPMENT_PASSWORD, YES))
result = click_runner.invoke(stake, mint_command, input=user_input, catch_exceptions=False)
@ -428,8 +428,8 @@ def test_prolong_interactive(click_runner,
final_period = surrogate_stakes[selected_index][sub_stake_index][1]
command = ('prolong',
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN)
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN)
user_input = '\n'.join((str(selected_index),
str(sub_stake_index),
@ -470,12 +470,12 @@ def test_prolong_non_interactive(click_runner,
final_period = surrogate_stakes[selected_index][sub_stake_index][1]
command = ('prolong',
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0],
'--index', sub_stake_index,
'--lock-periods', lock_periods,
'--force')
'--provider', MOCK_PROVIDER_URI,
'--network', TEMPORARY_DOMAIN,
'--staking-address', surrogate_stakers[0],
'--index', sub_stake_index,
'--lock-periods', lock_periods,
'--force')
user_input = INSECURE_DEVELOPMENT_PASSWORD
result = click_runner.invoke(stake, command, input=user_input, catch_exceptions=False)
@ -510,7 +510,7 @@ def test_divide_interactive(click_runner,
sub_stake_index = 1
lock_periods = 10
min_allowed_locked = token_economics.minimum_allowed_locked
target_value = min_allowed_locked
target_value = min_allowed_locked + 1 # Let's add some spare change to force dealing with decimal NU
mock_staking_agent.get_worker_from_staker.return_value = NULL_ADDRESS
@ -557,7 +557,7 @@ def test_divide_non_interactive(click_runner,
sub_stake_index = 1
lock_periods = 10
min_allowed_locked = token_economics.minimum_allowed_locked
target_value = min_allowed_locked
target_value = min_allowed_locked + 1 # Let's add some spare change to force dealing with decimal NU
mock_staking_agent.get_worker_from_staker.return_value = surrogate_stakers[0]
@ -604,7 +604,7 @@ def test_increase_interactive(click_runner,
selected_index = 0
sub_stake_index = 1
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10)
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10 + 12345)
mock_token_agent.get_balance.return_value = 0
@ -671,7 +671,7 @@ def test_increase_non_interactive(click_runner,
mock_refresh_stakes = mocker.spy(Staker, 'refresh_stakes')
sub_stake_index = 1
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10)
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10 + 12345)
locked_tokens = token_economics.minimum_allowed_locked * 5
mock_staking_agent.get_locked_tokens.return_value = locked_tokens
@ -722,7 +722,7 @@ def test_increase_lock_interactive(click_runner,
selected_index = 0
sub_stake_index = len(surrogate_stakes) - 1
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10)
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10 + 12345)
mock_staking_agent.calculate_staking_reward.return_value = 0
@ -789,7 +789,7 @@ def test_increase_lock_non_interactive(click_runner,
selected_index = 0
sub_stake_index = len(surrogate_stakes) - 1
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10)
additional_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10 + 12345)
mock_staking_agent.get_locked_tokens.return_value = token_economics.minimum_allowed_locked * 2
unlocked_tokens = token_economics.minimum_allowed_locked * 5
@ -838,7 +838,7 @@ def test_create_interactive(click_runner,
selected_index = 0
lock_periods = 366
value = NU.from_nunits(token_economics.minimum_allowed_locked * 11)
value = NU.from_nunits(token_economics.minimum_allowed_locked * 11 + 12345)
command = ('create',
'--provider', MOCK_PROVIDER_URI,
@ -943,7 +943,7 @@ def test_create_non_interactive(click_runner,
selected_index = 0
lock_periods = token_economics.minimum_locked_periods
value = NU.from_nunits(token_economics.minimum_allowed_locked * 2)
value = NU.from_nunits(token_economics.minimum_allowed_locked * 2 + 12345)
locked_tokens = token_economics.minimum_allowed_locked * 5
mock_staking_agent.get_locked_tokens.return_value = locked_tokens
@ -1000,7 +1000,7 @@ def test_create_lock_interactive(click_runner,
selected_index = 0
lock_periods = 366
value = NU.from_nunits(token_economics.minimum_allowed_locked * 2)
value = NU.from_nunits(token_economics.minimum_allowed_locked * 2 + 12345)
mock_staking_agent.calculate_staking_reward.return_value = token_economics.minimum_allowed_locked - 1
@ -1077,7 +1077,7 @@ def test_create_lock_non_interactive(click_runner,
selected_index = 0
lock_periods = token_economics.minimum_locked_periods
value = NU.from_nunits(token_economics.minimum_allowed_locked * 11)
value = NU.from_nunits(token_economics.minimum_allowed_locked * 11 + 12345)
mock_staking_agent.get_locked_tokens.return_value = token_economics.minimum_allowed_locked * 5
unlocked_tokens = token_economics.maximum_allowed_locked // 2