mirror of https://github.com/nucypher/nucypher.git
Prolong stake API and CLI entry; Deprecate Felix template and landing page
parent
c28d5892bb
commit
923b2deb98
|
@ -795,6 +795,42 @@ class Staker(NucypherTokenActor):
|
|||
|
||||
return new_stake
|
||||
|
||||
@only_me
|
||||
def prolong_stake(self,
|
||||
stake_index: int,
|
||||
additional_periods: int = None,
|
||||
expiration: maya.MayaDT = None) -> tuple:
|
||||
|
||||
# Calculate duration in periods
|
||||
if additional_periods and expiration:
|
||||
raise ValueError("Pass the number of lock periods or an expiration MayaDT; not both.")
|
||||
|
||||
# Update staking cache element
|
||||
stakes = self.stakes
|
||||
|
||||
# Select stake to divide from local cache
|
||||
try:
|
||||
current_stake = stakes[stake_index]
|
||||
except KeyError:
|
||||
if len(stakes):
|
||||
message = f"Cannot prolong stake - No stake exists with index {stake_index}."
|
||||
else:
|
||||
message = "Cannot prolong stake - There are no active stakes."
|
||||
raise Stake.StakingError(message)
|
||||
|
||||
# Calculate stake duration in periods
|
||||
if expiration:
|
||||
additional_periods = datetime_to_period(datetime=expiration, seconds_per_period=self.economics.seconds_per_period) - current_stake.final_locked_period
|
||||
if additional_periods <= 0:
|
||||
raise Stake.StakingError(f"New expiration {expiration} must be at least 1 period from the "
|
||||
f"current stake's end period ({current_stake.final_locked_period}).")
|
||||
|
||||
stake = current_stake.prolong(additional_periods=additional_periods)
|
||||
|
||||
# Update staking cache element
|
||||
self.stakes.refresh()
|
||||
return stake
|
||||
|
||||
def deposit(self, amount: int, lock_periods: int) -> Tuple[str, str]:
|
||||
"""Public facing method for token locking."""
|
||||
if self.is_contract:
|
||||
|
|
|
@ -455,6 +455,15 @@ class Stake:
|
|||
log.info(f"{staker.checksum_address} Initialized new stake: {amount} tokens for {lock_periods} periods")
|
||||
return stake
|
||||
|
||||
def prolong(self, additional_periods: int):
|
||||
self.sync()
|
||||
if self.is_expired:
|
||||
raise self.StakingError(f'Cannot divide an expired stake. Selected stake expired {self.unlock_datetime}.')
|
||||
receipt = self.staking_agent.prolong_stake(staker_address=self.staker_address,
|
||||
stake_index=self.index,
|
||||
periods=additional_periods)
|
||||
return receipt
|
||||
|
||||
|
||||
class WorkTracker:
|
||||
|
||||
|
|
|
@ -205,11 +205,6 @@ class Felix(Character, NucypherTokenActor):
|
|||
}
|
||||
)
|
||||
|
||||
@rest_app.route("/", methods=['GET'])
|
||||
def home():
|
||||
rendering = render_template(self.TEMPLATE_NAME)
|
||||
return rendering
|
||||
|
||||
@rest_app.route("/register", methods=['POST'])
|
||||
def register():
|
||||
"""Handle new recipient registration via POST request."""
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import functools
|
||||
import json
|
||||
|
||||
import click
|
||||
|
|
|
@ -36,7 +36,7 @@ from nucypher.cli.actions import (
|
|||
confirm_deployment,
|
||||
establish_deployer_registry
|
||||
)
|
||||
from nucypher.cli.common_options import (
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_config_root,
|
||||
option_etherscan,
|
||||
|
@ -44,7 +44,7 @@ from nucypher.cli.common_options import (
|
|||
option_hw_wallet,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
)
|
||||
)
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.painting import (
|
||||
paint_staged_deployment,
|
||||
|
|
|
@ -636,6 +636,71 @@ def divide(general_config, transacting_staker_options, config_file, force, value
|
|||
painting.paint_stakes(emitter=emitter, stakes=STAKEHOLDER.stakes)
|
||||
|
||||
|
||||
@stake.command()
|
||||
@group_transacting_staker_options
|
||||
@option_config_file
|
||||
@option_force
|
||||
@option_lock_periods
|
||||
@click.option('--index', help="The staker-specific stake index to prolong", type=click.INT)
|
||||
@group_general_config
|
||||
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 = handle_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 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)
|
||||
|
||||
#
|
||||
# Prolong
|
||||
#
|
||||
|
||||
# Interactive
|
||||
if not lock_periods:
|
||||
stake_extension_range = click.IntRange(min=1, max=economics.maximum_allowed_locked, clamp=False)
|
||||
max_extension = economics.maximum_allowed_locked - current_stake.periods_remaining
|
||||
lock_periods = click.prompt(f"Enter number of periods to extend (1-{max_extension})", type=stake_extension_range)
|
||||
if not force:
|
||||
click.confirm(f"Publish stake extension of {lock_periods} period(s) to the blockchain?", abort=True)
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
# 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("Current period advanced before transaction was broadcasted. Please try again.", red='red')
|
||||
raise click.Abort
|
||||
|
||||
# Authenticate and Execute
|
||||
STAKEHOLDER.assimilate(checksum_address=current_stake.staker_address, password=password)
|
||||
emitter.echo("Broadcasting Stake Extension...", color='yellow')
|
||||
receipt = STAKEHOLDER.prolong_stake(stake_index=current_stake.index, additional_periods=lock_periods)
|
||||
|
||||
# Report
|
||||
emitter.echo('Successfully Prolonged Stake', color='green', verbosity=1)
|
||||
paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
|
||||
painting.paint_stakes(emitter=emitter, stakes=STAKEHOLDER.stakes)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command('collect-reward')
|
||||
@group_transacting_staker_options
|
||||
@option_config_file
|
||||
|
|
|
@ -232,14 +232,14 @@ def test_prolong_stake(agency, testerchain, test_registry):
|
|||
staker_account, worker_account, *other = testerchain.unassigned_accounts
|
||||
|
||||
stakes = list(staking_agent.get_all_stakes(staker_address=staker_account))
|
||||
original_termination = stakes[1]
|
||||
original_termination = stakes[0][1]
|
||||
|
||||
receipt = staking_agent.prolong_stake(staker_account=staker_account, stake_index=0, periods=1)
|
||||
receipt = staking_agent.prolong_stake(staker_address=staker_account, stake_index=0, periods=1)
|
||||
assert receipt['status'] == 1
|
||||
|
||||
# Ensure stake was extended by one period.
|
||||
stakes = list(staking_agent.get_all_stakes(staker_address=staker_account))
|
||||
new_termination = stakes[1]
|
||||
new_termination = stakes[0][1]
|
||||
assert new_termination == original_termination + 1
|
||||
|
||||
|
||||
|
|
|
@ -113,10 +113,6 @@ def test_run_felix(click_runner,
|
|||
web_app = felix.make_web_app()
|
||||
test_client = web_app.test_client()
|
||||
|
||||
# Load the landing page
|
||||
response = test_client.get('/')
|
||||
assert response.status_code == 200
|
||||
|
||||
# Register a new recipient
|
||||
response = test_client.post('/register', data={'address': testerchain.client.accounts[-1]})
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -18,8 +18,6 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
import random
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from nucypher.blockchain.eth.agents import (
|
||||
PolicyManagerAgent,
|
||||
StakingEscrowAgent,
|
||||
|
@ -27,9 +25,8 @@ from nucypher.blockchain.eth.agents import (
|
|||
NucypherTokenAgent,
|
||||
ContractAgency
|
||||
)
|
||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.cli.status import status
|
||||
from nucypher.cli.commands.status import status
|
||||
from nucypher.utilities.sandbox.constants import TEST_PROVIDER_URI, MOCK_REGISTRY_FILEPATH
|
||||
|
||||
|
||||
|
|
|
@ -173,6 +173,38 @@ def test_staker_divide_stakes(click_runner,
|
|||
assert str(NU(token_economics.minimum_allowed_locked, 'NuNit').to_tokens()) in result.output
|
||||
|
||||
|
||||
def test_stake_prolong(click_runner,
|
||||
testerchain,
|
||||
test_registry,
|
||||
manual_staker,
|
||||
manual_worker,
|
||||
stakeholder_configuration_file_location):
|
||||
|
||||
prolong_args = ('stake', 'prolong',
|
||||
'--config-file', stakeholder_configuration_file_location,
|
||||
'--index', 0,
|
||||
'--lock-periods', 1,
|
||||
'--staking-address', manual_staker,
|
||||
'--force')
|
||||
|
||||
staker = Staker(is_me=True, checksum_address=manual_staker, registry=test_registry)
|
||||
staker.stakes.refresh()
|
||||
stake = staker.stakes[0]
|
||||
old_termination = stake.final_locked_period
|
||||
|
||||
user_input = INSECURE_DEVELOPMENT_PASSWORD
|
||||
result = click_runner.invoke(nucypher_cli,
|
||||
prolong_args,
|
||||
input=user_input,
|
||||
catch_exceptions=False)
|
||||
assert result.exit_code == 0
|
||||
|
||||
# Ensure Integration with Stakes
|
||||
stake.sync()
|
||||
new_termination = stake.final_locked_period
|
||||
assert new_termination == old_termination + 1
|
||||
|
||||
|
||||
def test_stake_set_worker(click_runner,
|
||||
testerchain,
|
||||
test_registry,
|
||||
|
@ -194,7 +226,6 @@ def test_stake_set_worker(click_runner,
|
|||
assert result.exit_code == 0
|
||||
|
||||
staker = Staker(is_me=True, checksum_address=manual_staker, registry=test_registry)
|
||||
|
||||
assert staker.worker_address == manual_worker
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue