Merge pull request #2049 from cygnusv/wlfix

Bugfixes to WorkLock command
pull/2052/head
K Prasch 2020-05-27 10:07:51 -07:00 committed by GitHub
commit 1bc281ac17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 79 deletions

View File

@ -1760,7 +1760,7 @@ class Bidder(NucypherTokenActor):
def place_bid(self, value: int) -> dict:
self.ensure_bidding_is_open()
minimum = self.worklock_agent.minimum_allowed_bid
if value < minimum:
if not self.get_deposited_eth and value < minimum:
raise self.BidderError(f"{prettify_eth_amount(value)} is too small a value for bidding; "
f"bid must be at least {prettify_eth_amount(minimum)}")
receipt = self.worklock_agent.bid(checksum_address=self.checksum_address, value=value)

View File

@ -44,6 +44,7 @@ from nucypher.cli.literature import (
COLLECTING_ETH_REWARD,
COLLECTING_PREALLOCATION_REWARD,
COLLECTING_TOKEN_REWARD,
CONFIRM_BROADCAST_CREATE_STAKE,
CONFIRM_BROADCAST_STAKE_DIVIDE,
CONFIRM_DISABLE_RESTAKING, CONFIRM_DISABLE_WIND_DOWN,
CONFIRM_NEW_MIN_POLICY_RATE,
@ -505,7 +506,7 @@ def create(general_config, transacting_staker_options, config_file, force, value
confirm_staged_stake(staker_address=staking_address, value=value, lock_periods=lock_periods)
# Last chance to bail
click.confirm(CONFIRM_BROADCAST_STAKE_DIVIDE, abort=True)
click.confirm(CONFIRM_BROADCAST_CREATE_STAKE, abort=True)
# Authenticate
password = transacting_staker_options.get_password(blockchain, client_account)

View File

@ -20,7 +20,6 @@ import maya
import os
import tabulate
from decimal import Decimal
from typing import Optional
from web3 import Web3
from nucypher.blockchain.eth.actors import Bidder
@ -31,13 +30,15 @@ from nucypher.blockchain.eth.utils import prettify_eth_amount
from nucypher.cli.actions.auth import get_client_password
from nucypher.cli.actions.select import select_client_account
from nucypher.cli.utils import connect_to_blockchain, get_registry, setup_emitter
from nucypher.cli.config import group_general_config
from nucypher.cli.config import group_general_config, GroupGeneralConfig
from nucypher.cli.literature import (
AVAILABLE_CLAIM_NOTICE,
BIDDERS_ALREADY_VERIFIED,
BIDDING_WINDOW_CLOSED,
BIDS_VALID_NO_FORCE_REFUND_INDICATED,
CANCELLATION_WINDOW_CLOSED,
CLAIM_ALREADY_PLACED,
CLAIMING_NOT_AVAILABLE,
COMPLETED_BID_VERIFICATION,
CONFIRM_BID_VERIFICATION,
CONFIRM_COLLECT_WORKLOCK_REFUND,
@ -100,6 +101,16 @@ class WorkLockOptions:
blockchain = connect_to_blockchain(emitter=emitter, provider_uri=self.provider_uri)
return emitter, registry, blockchain
def get_bidder_address(self, emitter, registry):
if not self.bidder_address:
self.bidder_address = select_client_account(emitter=emitter,
provider_uri=self.provider_uri,
signer_uri=self.signer_uri,
network=self.network,
registry=registry,
show_eth_balance=True)
return self.bidder_address
def __create_bidder(self,
registry,
transacting: bool = True,
@ -142,7 +153,7 @@ def worklock():
@worklock.command()
@group_worklock_options
@group_general_config
def status(general_config, worklock_options):
def status(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions):
"""Show current WorkLock information"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
paint_worklock_status(emitter=emitter, registry=registry)
@ -157,7 +168,11 @@ def status(general_config, worklock_options):
@option_force
@option_hw_wallet
@click.option('--value', help="ETH value of bid", type=DecimalRange(min=0))
def bid(general_config, worklock_options, force, hw_wallet, value):
def bid(general_config: GroupGeneralConfig,
worklock_options: WorkLockOptions,
force: bool,
hw_wallet: bool,
value: Decimal):
"""Place a bid, or increase an existing bid"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry) # type: WorkLockAgent
@ -166,21 +181,14 @@ def bid(general_config, worklock_options, force, hw_wallet, value):
emitter.echo(BIDDING_WINDOW_CLOSED, color='red')
raise click.Abort()
if not worklock_options.bidder_address:
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
poa=worklock_options.poa,
network=worklock_options.network,
registry=registry,
show_eth_balance=True)
_bidder_address = worklock_options.get_bidder_address(emitter, registry)
bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)
existing_bid_amount = bidder.get_deposited_eth
if not value:
if force:
raise click.MissingParameter("Missing --value.")
existing_bid_amount = bidder.get_deposited_eth
if not existing_bid_amount: # It's the first bid
minimum_bid = bidder.worklock_agent.minimum_allowed_bid
minimum_bid_in_eth = Web3.fromWei(minimum_bid, 'ether')
@ -194,17 +202,22 @@ def bid(general_config, worklock_options, force, hw_wallet, value):
value = int(Web3.toWei(Decimal(value), 'ether'))
if not force:
paint_bidding_notice(emitter=emitter, bidder=bidder)
click.confirm(f"Place WorkLock bid of {prettify_eth_amount(value)}?", abort=True)
if not existing_bid_amount:
paint_bidding_notice(emitter=emitter, bidder=bidder)
click.confirm(f"Place WorkLock bid of {prettify_eth_amount(value)}?", abort=True)
else:
click.confirm(f"Increase current bid ({prettify_eth_amount(existing_bid_amount)}) "
f"by {prettify_eth_amount(value)}?", abort=True)
receipt = bidder.place_bid(value=value)
emitter.message("Publishing WorkLock Bid...")
maximum = NU.from_nunits(bidder.economics.maximum_allowed_locked)
available_claim = NU.from_nunits(bidder.available_claim)
message = f'Current bid: {prettify_eth_amount(bidder.get_deposited_eth)} | Claim: {available_claim}\n'
message = f'\nCurrent bid: {prettify_eth_amount(bidder.get_deposited_eth)} | Claim: {available_claim}\n'
if available_claim > maximum:
message += f"This claim is currently above the allowed max ({maximum}), so the bid may be partially refunded.\n"
message += f"\nThis claim is currently above the allowed max ({maximum}), " \
f"so the bid may be partially refunded.\n"
message += f'Note that available claim value may fluctuate until bidding closes and claims are finalized.\n'
emitter.echo(message, color='yellow')
@ -216,27 +229,21 @@ def bid(general_config, worklock_options, force, hw_wallet, value):
@group_worklock_options
@option_force
@option_hw_wallet
def cancel_bid(general_config, worklock_options, force, hw_wallet):
def cancel_bid(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions, force: bool, hw_wallet: bool):
"""Cancel your bid and receive your ETH back"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry) # type: WorkLockAgent
now = maya.now().epoch
if not worklock_agent.start_bidding_date <= now <= worklock_agent.end_cancellation_date:
raise click.Abort(f"You can't cancel your bid. The cancellation window is closed.")
emitter.echo(CANCELLATION_WINDOW_CLOSED, color='red')
raise click.Abort()
if not worklock_options.bidder_address: # TODO: Consider bundle this in worklock_options
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
poa=worklock_options.poa,
network=worklock_options.network,
show_eth_balance=True,
registry=registry)
bidder_address = worklock_options.get_bidder_address(emitter, registry)
bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)
if not force:
value = bidder.get_deposited_eth
click.confirm(f"Confirm bid cancellation of {prettify_eth_amount(value)}"
f" for {worklock_options.bidder_address}?", abort=True)
click.confirm(f"Confirm bid cancellation of {prettify_eth_amount(value)} for {bidder_address}?", abort=True)
receipt = bidder.cancel_bid()
emitter.echo(SUCCESSFUL_BID_CANCELLATION, color='green')
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name)
@ -248,28 +255,22 @@ def cancel_bid(general_config, worklock_options, force, hw_wallet):
@option_hw_wallet
@group_worklock_options
@group_general_config
def claim(general_config, worklock_options, force, hw_wallet):
def claim(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions, force: bool, hw_wallet: bool):
"""Claim tokens for your bid, and start staking them"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry) # type: WorkLockAgent
if not worklock_agent.is_claiming_available():
raise click.Abort(f"You can't claim tokens. Claiming is not currently available.")
if not worklock_options.bidder_address:
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
poa=worklock_options.poa,
network=worklock_options.network,
registry=registry,
show_eth_balance=True)
emitter.echo(CLAIMING_NOT_AVAILABLE, color='red')
raise click.Abort()
bidder_address = worklock_options.get_bidder_address(emitter, registry)
bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)
unspent_bid = bidder.available_compensation
if unspent_bid:
emitter.echo(WORKLOCK_ADDITIONAL_COMPENSATION_AVAILABLE.format(amount=prettify_eth_amount(unspent_bid)))
if not force:
message = CONFIRM_REQUEST_WORKLOCK_COMPENSATION.format(bidder_address=worklock_options.bidder_address)
message = CONFIRM_REQUEST_WORKLOCK_COMPENSATION.format(bidder_address=bidder_address)
click.confirm(message, abort=True)
emitter.echo(REQUESTING_WORKLOCK_COMPENSATION)
receipt = bidder.withdraw_compensation()
@ -278,20 +279,20 @@ def claim(general_config, worklock_options, force, hw_wallet):
has_claimed = bidder.has_claimed
if bool(has_claimed):
emitter.echo(CLAIM_ALREADY_PLACED.format(bidder_address=bidder.checksum_address), color='red')
return
raise click.Abort()
tokens = NU.from_nunits(bidder.available_claim)
emitter.echo(AVAILABLE_CLAIM_NOTICE.format(tokens=tokens), color='green', bold=True)
if not force:
lock_duration = bidder.worklock_agent.worklock_parameters()[-2]
emitter.echo(WORKLOCK_CLAIM_ADVISORY.format(lock_duration=lock_duration), color='blue')
click.confirm(CONFIRM_WORKLOCK_CLAIM.format(bidder_address=worklock_options.bidder_address), abort=True)
click.confirm(CONFIRM_WORKLOCK_CLAIM.format(bidder_address=bidder_address), abort=True)
emitter.echo(SUBMITTING_WORKLOCK_CLAIM)
receipt = bidder.claim()
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name)
paint_worklock_claim(emitter=emitter,
bidder_address=worklock_options.bidder_address,
bidder_address=bidder_address,
network=worklock_options.network,
provider_uri=worklock_options.provider_uri)
@ -299,20 +300,12 @@ def claim(general_config, worklock_options, force, hw_wallet):
@worklock.command()
@group_worklock_options
@group_general_config
def remaining_work(general_config, worklock_options):
def remaining_work(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions):
"""Check how much work is pending until you can get all your locked ETH back"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
if not worklock_options.bidder_address:
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
poa=worklock_options.poa,
network=worklock_options.network,
registry=registry,
show_eth_balance=True)
bidder_address = worklock_options.get_bidder_address(emitter, registry)
bidder = worklock_options.create_transactionless_bidder(registry=registry)
_remaining_work = bidder.remaining_work
emitter.echo(f"Work Remaining for {worklock_options.bidder_address}: {_remaining_work}")
emitter.echo(f"Work Remaining for {bidder_address}: {bidder.remaining_work}")
@worklock.command()
@ -320,18 +313,13 @@ def remaining_work(general_config, worklock_options):
@option_hw_wallet
@group_worklock_options
@group_general_config
def refund(general_config, worklock_options, force, hw_wallet):
def refund(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions, force: bool, hw_wallet: bool):
"""Reclaim ETH unlocked by your work"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
if not worklock_options.bidder_address:
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
poa=worklock_options.poa,
network=worklock_options.network,
registry=registry,
show_eth_balance=True)
bidder_address = worklock_options.get_bidder_address(emitter, registry)
if not force:
click.confirm(CONFIRM_COLLECT_WORKLOCK_REFUND.format(bidder_Address=worklock_options.bidder_address), abort=True)
click.confirm(CONFIRM_COLLECT_WORKLOCK_REFUND.format(bidder_Address=bidder_address), abort=True)
emitter.echo(SUBMITTING_WORKLOCK_REFUND_REQUEST)
bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)
@ -346,15 +334,14 @@ def refund(general_config, worklock_options, force, hw_wallet):
@option_hw_wallet
@click.option('--gas-limit', help="Gas limit per each verification transaction", type=click.IntRange(min=60000))
# TODO: Consider moving to administrator (nucypher-deploy) #1758
def enable_claiming(general_config, worklock_options, force, hw_wallet, gas_limit):
def enable_claiming(general_config: GroupGeneralConfig,
worklock_options: WorkLockOptions,
force: bool,
hw_wallet: bool,
gas_limit: int):
"""Ensure correctness of bidding and enable claiming"""
emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
if not worklock_options.bidder_address: # TODO: Consider bundle this in worklock_options
worklock_options.bidder_address = select_client_account(emitter=emitter,
provider_uri=worklock_options.provider_uri,
network=worklock_options.network,
registry=registry,
show_eth_balance=True)
bidder_address = worklock_options.get_bidder_address(emitter, registry)
bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)
whales = bidder.get_whales()
@ -364,8 +351,7 @@ def enable_claiming(general_config, worklock_options, force, hw_wallet, gas_limi
emitter.echo(tabulate.tabulate(dict(zip(headers, columns)), headers=headers, floatfmt="fancy_grid"))
if not force:
click.confirm(f"Confirm force refund to at least {len(whales)} bidders"
f" using {worklock_options.bidder_address}?", abort=True)
click.confirm(f"Confirm force refund to at least {len(whales)} bidders using {bidder_address}?", abort=True)
force_refund_receipt = bidder.force_refund()
emitter.echo(WHALE_WARNING.format(number=len(whales)), color='green')
@ -388,7 +374,7 @@ def enable_claiming(general_config, worklock_options, force, hw_wallet, gas_limi
bidders_per_transaction = bidder.worklock_agent.estimate_verifying_correctness(gas_limit=gas_limit)
if not force:
message = CONFIRM_BID_VERIFICATION.format(bidder_address=worklock_options.bidder_address,
message = CONFIRM_BID_VERIFICATION.format(bidder_address=bidder_address,
gas_limit=gas_limit,
bidders_per_transaction=bidders_per_transaction)
confirmation = click.confirm(message)

View File

@ -79,6 +79,8 @@ CONFIRM_LARGE_STAKE_VALUE = "Wow, {value} - That's a lot of NU - Are you sure th
CONFIRM_LARGE_STAKE_DURATION = "Woah, {lock_periods} is a long time - Are you sure this is correct?"
CONFIRM_BROADCAST_CREATE_STAKE = "Publish staged stake to the blockchain?"
PREALLOCATION_STAKE_ADVISORY = "Beneficiary {client_account} will use preallocation contract {staking_address} to stake."
NO_STAKING_ACCOUNTS = "No staking accounts found."
@ -452,6 +454,8 @@ Accept WorkLock terms and node operator obligation?""" # TODO: Show a special m
BIDDING_WINDOW_CLOSED = f"You can't bid, the bidding window is closed."
CANCELLATION_WINDOW_CLOSED = "You can't cancel your bid. The cancellation window is closed."
SUCCESSFUL_BID_CANCELLATION = "Bid canceled\n"
WORKLOCK_ADDITIONAL_COMPENSATION_AVAILABLE = """
@ -468,6 +472,8 @@ Would you like to proceed?
REQUESTING_WORKLOCK_COMPENSATION = "Requesting refund of unspent bid amount..."
CLAIMING_NOT_AVAILABLE = "You can't claim tokens yet. Claiming is not currently available."
CLAIM_ALREADY_PLACED = "Claim was already placed for {bidder_address}"
AVAILABLE_CLAIM_NOTICE = "\nYou have an available claim of {tokens} 🎉 \n"

View File

@ -26,11 +26,11 @@ from nucypher.cli.literature import SUCCESSFUL_WORKLOCK_CLAIM, WORKLOCK_AGREEMEN
def paint_bidding_notice(emitter, bidder):
WORKLOCK_AGREEMENT.format(refund_rate=prettify_eth_amount(bidder.worklock_agent.get_bonus_refund_rate()),
end_date=maya.MayaDT(bidder.economics.bidding_end_date).local_datetime(),
bidder_address=bidder.checksum_address,
duration=bidder.economics.worklock_commitment_duration)
emitter.echo(WORKLOCK_AGREEMENT)
message = WORKLOCK_AGREEMENT.format(refund_rate=prettify_eth_amount(bidder.worklock_agent.get_bonus_refund_rate()),
end_date=maya.MayaDT(bidder.economics.bidding_end_date).local_datetime(),
bidder_address=bidder.checksum_address,
duration=bidder.economics.worklock_commitment_duration)
emitter.echo(message)
return