mirror of https://github.com/nucypher/nucypher.git
Stake command to control snapshots flag
parent
ae20a749b4
commit
719b35889e
|
@ -1243,6 +1243,28 @@ class Staker(NucypherTokenActor):
|
|||
receipt = self._set_winding_down(value=False)
|
||||
return receipt
|
||||
|
||||
@property
|
||||
def is_taking_snapshots(self) -> bool:
|
||||
winding_down = self.staking_agent.is_taking_snapshots(staker_address=self.checksum_address)
|
||||
return winding_down
|
||||
|
||||
@only_me
|
||||
@save_receipt
|
||||
def _set_snapshots(self, value: bool) -> TxReceipt:
|
||||
# if self.is_contract:
|
||||
# receipt = self.preallocation_escrow_agent.set_snapshots(activate=value)
|
||||
# else:
|
||||
receipt = self.staking_agent.set_snapshots(staker_address=self.checksum_address, activate=value)
|
||||
return receipt
|
||||
|
||||
def enable_snapshots(self) -> TxReceipt:
|
||||
receipt = self._set_snapshots(value=True)
|
||||
return receipt
|
||||
|
||||
def disable_snapshots(self) -> TxReceipt:
|
||||
receipt = self._set_snapshots(value=False)
|
||||
return receipt
|
||||
|
||||
def non_withdrawable_stake(self) -> NU:
|
||||
staked_amount: NuNits = self.staking_agent.non_withdrawable_stake(staker_address=self.checksum_address)
|
||||
return NU.from_nunits(staked_amount)
|
||||
|
|
|
@ -32,7 +32,7 @@ from nucypher.cli.literature import (
|
|||
CONFIRM_STAGED_STAKE,
|
||||
RESTAKING_AGREEMENT,
|
||||
RESTAKING_LOCK_AGREEMENT,
|
||||
WINDING_DOWN_AGREEMENT
|
||||
WINDING_DOWN_AGREEMENT, SNAPSHOTS_DISABLING_AGREEMENT, CONFIRM_DISABLE_SNAPSHOTS
|
||||
)
|
||||
from nucypher.config.node import CharacterConfiguration
|
||||
|
||||
|
@ -75,6 +75,13 @@ def confirm_enable_winding_down(emitter: StdoutEmitter, staking_address: str) ->
|
|||
return True
|
||||
|
||||
|
||||
def confirm_disable_snapshots(emitter: StdoutEmitter, staking_address: str) -> bool:
|
||||
"""Interactively confirm disabling of taking snapshots with user agreements."""
|
||||
emitter.message(SNAPSHOTS_DISABLING_AGREEMENT)
|
||||
click.confirm(CONFIRM_DISABLE_SNAPSHOTS.format(staking_address=staking_address), abort=True)
|
||||
return True
|
||||
|
||||
|
||||
def confirm_staged_stake(staker_address: str, value: NU, lock_periods: int) -> bool:
|
||||
"""Interactively confirm a new stake reviewing all staged stake details."""
|
||||
click.confirm(CONFIRM_STAGED_STAKE.format(nunits=str(value.to_nunits()),
|
||||
|
|
|
@ -33,7 +33,7 @@ from nucypher.cli.actions.confirm import (
|
|||
confirm_enable_restaking_lock,
|
||||
confirm_enable_winding_down,
|
||||
confirm_large_stake,
|
||||
confirm_staged_stake
|
||||
confirm_staged_stake, confirm_disable_snapshots
|
||||
)
|
||||
from nucypher.cli.actions.select import select_client_account_for_staking, select_stake
|
||||
from nucypher.cli.utils import setup_emitter
|
||||
|
@ -70,7 +70,8 @@ from nucypher.cli.literature import (
|
|||
CONFIRM_COLLECTING_WITHOUT_MINTING, NO_TOKENS_TO_WITHDRAW, NO_FEE_TO_WITHDRAW, CONFIRM_INCREASING_STAKE,
|
||||
PROMPT_STAKE_INCREASE_VALUE, SUCCESSFUL_STAKE_INCREASE, INSUFFICIENT_BALANCE_TO_INCREASE, MAXIMUM_STAKE_REACHED,
|
||||
INSUFFICIENT_BALANCE_TO_CREATE, PROMPT_STAKE_CREATE_VALUE, PROMPT_DEPOSIT_OR_LOCK, PROMPT_STAKE_CREATE_LOCK_PERIODS,
|
||||
ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE, CONFIRM_MERGE, SUCCESSFUL_STAKES_MERGE
|
||||
ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE, CONFIRM_MERGE, SUCCESSFUL_STAKES_MERGE, CONFIRM_DISABLE_SNAPSHOTS,
|
||||
SUCCESSFUL_ENABLE_SNAPSHOTS, SUCCESSFUL_DISABLE_SNAPSHOTS, CONFIRM_ENABLE_SNAPSHOTS
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
|
@ -732,6 +733,52 @@ def winddown(general_config, transacting_staker_options, config_file, enable, fo
|
|||
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=blockchain.client.chain_name)
|
||||
|
||||
|
||||
@stake.command()
|
||||
@group_transacting_staker_options
|
||||
@option_config_file
|
||||
@click.option('--enable/--disable', help="Used to enable and disable taking snapshots", is_flag=True, default=True)
|
||||
@option_force
|
||||
@group_general_config
|
||||
def snapshots(general_config, transacting_staker_options, config_file, enable, force):
|
||||
"""Manage snapshots with --enable or --disable."""
|
||||
|
||||
# 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)
|
||||
|
||||
# Inner Exclusive Switch
|
||||
if enable:
|
||||
if not force:
|
||||
click.confirm(CONFIRM_ENABLE_SNAPSHOTS.format(staking_address=staking_address), abort=True)
|
||||
|
||||
# Authenticate and Execute
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
STAKEHOLDER.assimilate(password=password)
|
||||
|
||||
receipt = STAKEHOLDER.enable_snapshots()
|
||||
emitter.echo(SUCCESSFUL_ENABLE_SNAPSHOTS.format(staking_address=staking_address), color='green', verbosity=1)
|
||||
else:
|
||||
if not force:
|
||||
confirm_disable_snapshots(emitter, staking_address=staking_address)
|
||||
|
||||
# Authenticate and Execute
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
STAKEHOLDER.assimilate(password=password)
|
||||
|
||||
receipt = STAKEHOLDER.disable_snapshots()
|
||||
emitter.echo(SUCCESSFUL_DISABLE_SNAPSHOTS.format(staking_address=staking_address), color='green', verbosity=1)
|
||||
|
||||
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=blockchain.client.chain_name)
|
||||
|
||||
|
||||
@stake.command()
|
||||
@group_transacting_staker_options
|
||||
@option_config_file
|
||||
|
|
|
@ -191,6 +191,22 @@ CONFIRM_DISABLE_RESTAKING = "Confirm disable re-staking for staker {staking_addr
|
|||
SUCCESSFUL_DISABLE_RESTAKING = 'Successfully disabled re-staking for {staking_address}'
|
||||
|
||||
|
||||
#
|
||||
# Snapshots
|
||||
#
|
||||
SNAPSHOTS_DISABLING_AGREEMENT = """
|
||||
By disabling the taking snapshots for {staking_address}, specified address will be excluded in all future DAO validations
|
||||
until snapshots will be enabled again.
|
||||
"""
|
||||
|
||||
CONFIRM_ENABLE_SNAPSHOTS = "Confirm enable automatic taking snapshots for staker {staking_address}?"
|
||||
|
||||
SUCCESSFUL_ENABLE_SNAPSHOTS = 'Successfully enabled taking snapshots for {staking_address}'
|
||||
|
||||
CONFIRM_DISABLE_SNAPSHOTS = "Confirm disable taking snapshots for staker {staking_address}?"
|
||||
|
||||
SUCCESSFUL_DISABLE_SNAPSHOTS = 'Successfully disabled taking snapshots for {staking_address}'
|
||||
|
||||
#
|
||||
# Bonding
|
||||
#
|
||||
|
|
|
@ -27,7 +27,7 @@ from nucypher.cli.literature import POST_STAKING_ADVICE
|
|||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
|
||||
STAKE_TABLE_COLUMNS = ('Idx', 'Value', 'Remaining', 'Enactment', 'Termination', 'Status')
|
||||
STAKER_TABLE_COLUMNS = ('Status', 'Restaking', 'Winding Down', 'Unclaimed Fees', 'Min fee rate')
|
||||
STAKER_TABLE_COLUMNS = ('Status', 'Restaking', 'Winding Down', 'Snapshots', 'Unclaimed Fees', 'Min fee rate')
|
||||
|
||||
|
||||
def paint_all_stakes(emitter: StdoutEmitter,
|
||||
|
@ -73,6 +73,7 @@ def paint_stakes(emitter: StdoutEmitter,
|
|||
staker_data = [missing_info,
|
||||
f'{"Yes" if staker.is_restaking else "No"} ({"Locked" if staker.restaking_lock_enabled else "Unlocked"})',
|
||||
"Yes" if bool(staker.is_winding_down) else "No",
|
||||
"Yes" if bool(staker.is_taking_snapshots) else "No",
|
||||
pretty_fees,
|
||||
min_fee_rate]
|
||||
|
||||
|
|
|
@ -162,6 +162,7 @@ def paint_stakers(emitter, stakers: List[str], registry: BaseContractRegistry) -
|
|||
worker = staker.worker_address
|
||||
is_restaking = staker.is_restaking
|
||||
is_winding_down = staker.is_winding_down
|
||||
is_taking_snapshots = staker.is_taking_snapshots
|
||||
|
||||
missing_commitments = current_period - last_committed_period
|
||||
owned_in_nu = round(owned_tokens, 2)
|
||||
|
@ -180,6 +181,7 @@ def paint_stakers(emitter, stakers: List[str], registry: BaseContractRegistry) -
|
|||
else:
|
||||
emitter.echo(f"{tab} {'Re-staking:':10} No")
|
||||
emitter.echo(f"{tab} {'Winding down:':10} {'Yes' if is_winding_down else 'No'}")
|
||||
emitter.echo(f"{tab} {'Snapshots:':10} {'Yes' if is_taking_snapshots else 'No'}")
|
||||
emitter.echo(f"{tab} {'Activity:':10} ", nl=False)
|
||||
if missing_commitments == -1:
|
||||
emitter.echo(f"Next period committed (#{last_committed_period})", color='green')
|
||||
|
|
|
@ -354,6 +354,24 @@ def test_staker_manages_winding_down(testerchain,
|
|||
assert staker.locked_tokens(base_duration) == 0
|
||||
|
||||
|
||||
def test_staker_manages_snapshots(testerchain,
|
||||
test_registry,
|
||||
staker,
|
||||
token_economics,
|
||||
ursula_decentralized_test_config):
|
||||
# Disable taking snapshots
|
||||
testerchain.time_travel(periods=1)
|
||||
assert staker.is_taking_snapshots
|
||||
receipt = staker.disable_snapshots()
|
||||
assert receipt['status'] == 1
|
||||
assert not staker.is_taking_snapshots
|
||||
|
||||
# Enable taking snapshots
|
||||
receipt = staker.enable_snapshots()
|
||||
assert receipt['status'] == 1
|
||||
assert staker.is_taking_snapshots
|
||||
|
||||
|
||||
def test_set_min_fee_rate(testerchain, test_registry, staker):
|
||||
# Check before set
|
||||
_minimum, default, maximum = FEE_RATE_RANGE
|
||||
|
|
|
@ -490,6 +490,45 @@ def test_stake_winddown(click_runner,
|
|||
assert "Successfully disabled" in result.output
|
||||
|
||||
|
||||
def test_stake_snapshots(click_runner,
|
||||
manual_staker,
|
||||
custom_filepath,
|
||||
testerchain,
|
||||
agency_local_registry,
|
||||
stakeholder_configuration_file_location):
|
||||
|
||||
staker = Staker(is_me=True, checksum_address=manual_staker, registry=agency_local_registry)
|
||||
assert staker.is_taking_snapshots
|
||||
|
||||
restake_args = ('stake', 'snapshots',
|
||||
'--disable',
|
||||
'--config-file', stakeholder_configuration_file_location,
|
||||
'--staking-address', manual_staker,
|
||||
'--force')
|
||||
|
||||
result = click_runner.invoke(nucypher_cli,
|
||||
restake_args,
|
||||
input=INSECURE_DEVELOPMENT_PASSWORD,
|
||||
catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert not staker.is_taking_snapshots
|
||||
assert "Successfully disabled" in result.output
|
||||
|
||||
disable_args = ('stake', 'snapshots',
|
||||
'--enable',
|
||||
'--config-file', stakeholder_configuration_file_location,
|
||||
'--staking-address', manual_staker,
|
||||
'--force')
|
||||
|
||||
result = click_runner.invoke(nucypher_cli,
|
||||
disable_args,
|
||||
input=INSECURE_DEVELOPMENT_PASSWORD,
|
||||
catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
assert staker.is_taking_snapshots
|
||||
assert "Successfully enabled" in result.output
|
||||
|
||||
|
||||
def test_collect_rewards_integration(click_runner,
|
||||
testerchain,
|
||||
agency_local_registry,
|
||||
|
|
|
@ -98,7 +98,7 @@ MOCK_ALLOCATION_REGISTRY_FILEPATH = BASE_TEMP_DIR / f'{BASE_TEMP_PREFIX}test-all
|
|||
|
||||
MOCK_INDIVIDUAL_ALLOCATION_FILEPATH = BASE_TEMP_DIR / f'{BASE_TEMP_PREFIX}test-individual-allocation-{datetime.now().strftime(DATETIME_FORMAT)}.json'
|
||||
|
||||
MOCK_CUSTOM_INSTALLATION_PATH_2 = '/tmp/nucypher-tmp-test-custom-2-{}'.format(time.time())
|
||||
MOCK_CUSTOM_INSTALLATION_PATH_2 = BASE_TEMP_DIR / f'{BASE_TEMP_PREFIX}test-custom-2-{datetime.now().strftime(DATETIME_FORMAT)}'
|
||||
|
||||
MOCK_REGISTRY_FILEPATH = BASE_TEMP_DIR / f'{BASE_TEMP_PREFIX}mock-registry-{datetime.now().strftime(DATETIME_FORMAT)}.json'
|
||||
|
||||
|
|
Loading…
Reference in New Issue