def init(click_config, # Admin Options geth, provider_uri, network, registry_filepath, staker_address, worker_address, federated_only, rest_host, rest_port, db_filepath, poa, light, # Other force, config_root): """ Create a new Ursula node configuration. """ ### Setup ### _validate_args(geth, federated_only, staker_address, registry_filepath) emitter = _setup_emitter(click_config, worker_address) _pre_launch_warnings(emitter, dev=None, force=force) ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process() provider_uri = ETH_NODE.provider_uri(scheme='file') ############# if (not staker_address or not worker_address) and not federated_only: if not staker_address: prompt = "Select staker account" staker_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=provider_uri) if not worker_address: prompt = "Select worker account" worker_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=provider_uri) if not config_root: # Flag config_root = click_config.config_file # Envvar if not rest_host: rest_host = actions.determine_external_ip_address(emitter, force=force) ursula_config = UrsulaConfiguration.generate(password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, domains={network} if network else None, federated_only=federated_only, checksum_address=staker_address, worker_address=worker_address, registry_filepath=registry_filepath, provider_process=ETH_NODE, provider_uri=provider_uri, poa=poa, light=light) painting.paint_new_installation_help(emitter, new_configuration=ursula_config)
def init( click_config, # Admin Options provider_uri, network, registry_filepath, checksum_address, # Other federated_only, config_root): """ Create a brand new persistent Bob. """ emitter = _setup_emitter(click_config) if not config_root: # Flag config_root = click_config.config_file # Envvar if not checksum_address and not federated_only: checksum_address = select_client_account(emitter=emitter, provider_uri=provider_uri) new_bob_config = BobConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root or DEFAULT_CONFIG_ROOT, checksum_address=checksum_address, domains={network} if network else None, federated_only=federated_only, registry_filepath=registry_filepath, provider_uri=provider_uri) return painting.paint_new_installation_help( emitter, new_configuration=new_bob_config)
def generate_config(self, emitter, config_root): opts = self.config_options if opts.dev: raise click.BadArgumentUsage( "Cannot create a persistent development character") if not opts.provider_uri and not opts.federated_only: raise click.BadOptionUsage( option_name='--provider', message= "--provider is required to create a new decentralized alice.") pay_with = opts.pay_with if not pay_with and not opts.federated_only: pay_with = select_client_account(emitter=emitter, provider_uri=opts.provider_uri, show_eth_balance=True) return AliceConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=pay_with, domains=opts.domains, federated_only=opts.federated_only, provider_uri=opts.provider_uri, signer_uri=opts.signer_uri, provider_process=opts.eth_node, registry_filepath=opts.registry_filepath, poa=self.poa, light=self.light, m=self.m, n=self.n, duration_periods=self.duration_periods)
def allocations(general_config, actor_options, allocation_infile, allocation_outfile, sidekick_account): """ Deploy pre-allocation contracts. """ emitter = general_config.emitter ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter) if not sidekick_account and click.confirm('Do you want to use a sidekick account to assist during deployment?'): prompt = "Select sidekick account" sidekick_account = select_client_account(emitter=emitter, prompt=prompt, provider_uri=actor_options.provider_uri, registry=local_registry, show_balances=True) if not actor_options.force: click.confirm(f"Selected {sidekick_account} - Continue?", abort=True) if sidekick_account: password = None if not deployer_interface.client.is_local: password = get_client_password(checksum_address=sidekick_account) ADMINISTRATOR.recruit_sidekick(sidekick_address=sidekick_account, sidekick_password=password) if not allocation_infile: allocation_infile = click.prompt("Enter allocation data filepath") ADMINISTRATOR.deploy_beneficiaries_from_file(allocation_data_filepath=allocation_infile, allocation_outfile=allocation_outfile, emitter=emitter, interactive=not actor_options.force)
def claim(general_config, worklock_options, registry_options, force, hw_wallet): """Claim tokens for a successful bid, and start staking them""" emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account( emitter=emitter, provider_uri=registry_options.provider_uri, network=registry_options.network, show_balances=True) # TODO: Show amount of tokens to claim if not force: emitter.echo( "Note: Claiming WorkLock NU tokens will initialize a new stake.", color='blue') click.confirm( f"Continue worklock claim for bidder {worklock_options.bidder_address}?", abort=True) emitter.message("Submitting Claim...") registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) 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, network=registry_options.network, provider_uri=registry_options.provider_uri) return # Exit
def refund(general_config, worklock_options, force, hw_wallet): """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_balances=True) if not force: click.confirm( f"Collect ETH refund for bidder {worklock_options.bidder_address}?", abort=True) emitter.echo("Submitting WorkLock refund request...") bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) receipt = bidder.refund_deposit() paint_receipt_summary( receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def cancel_bid(general_config, registry_options, worklock_options, force, hw_wallet): """Cancel your bid""" emitter = _setup_emitter(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=registry_options.provider_uri, network=registry_options.network, show_balances=True) registry = registry_options.get_registry(emitter, general_config.debug) 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) receipt = bidder.cancel_bid() emitter.echo("Bid canceled\n", color='green') paint_receipt_summary( receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def generate_config(self, emitter, config_root, force): assert not self.dev staker_address = self.staker_address worker_address = self.worker_address if (not staker_address or not worker_address) and not self.federated_only: if not staker_address: staker_address = click.prompt("Enter staker address", type=EIP55_CHECKSUM_ADDRESS) if not worker_address: prompt = "Select worker account" worker_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, show_balances=False) rest_host = self.rest_host if not rest_host: rest_host = actions.determine_external_ip_address(emitter, force=force) return UrsulaConfiguration.generate(password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=self.rest_port, db_filepath=self.db_filepath, domains=self.domains, federated_only=self.federated_only, checksum_address=staker_address, worker_address=worker_address, registry_filepath=self.registry_filepath, provider_process=self.eth_node, provider_uri=self.provider_uri, poa=self.poa, light=self.light)
def cancel_bid(general_config, worklock_options, force, hw_wallet): """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.") 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_balances=True, registry=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) receipt = bidder.cancel_bid() emitter.echo("Bid canceled\n", color='green') paint_receipt_summary( receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig): """ Upgrade NuCypher existing proxy contract deployments. """ # Init emitter = general_config.emitter ADMINISTRATOR, _, _, registry = actor_options.create_actor(emitter, is_multisig=bool(multisig)) # FIXME: Workaround for building MultiSig TXs contract_name = actor_options.contract_name if not contract_name: raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade") if multisig: if not target_address: raise click.BadArgumentUsage(message="--multisig requires using --target-address.") if not actor_options.force: click.confirm(f"Confirm building a re-target transaction for {contract_name}'s proxy to {target_address}?", abort=True) transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address, just_build_transaction=True) trustee_address = select_client_account(emitter=emitter, prompt="Select trustee address", provider_uri=actor_options.provider_uri, show_balances=False) if not actor_options.force: click.confirm(f"Selected {trustee_address} - Continue?", abort=True) trustee = Trustee(registry=registry, checksum_address=trustee_address) transaction_proposal = trustee.create_transaction_proposal(transaction) emitter.message(f"Transaction to retarget {contract_name} proxy to {target_address} was built:", color='green') paint_multisig_proposed_transaction(emitter, transaction_proposal) # TODO: Show decoded function too filepath = f'proposal-{trustee.multisig_agent.contract_address[:8]}-TX-{transaction_proposal.nonce}.json' transaction_proposal.write(filepath=filepath) emitter.echo(f"Saved proposal to {filepath}", color='blue', bold=True) elif retarget: if not target_address: raise click.BadArgumentUsage(message="--target-address is required when using --retarget") if not actor_options.force: click.confirm(f"Confirm re-target {contract_name}'s proxy to {target_address}?", abort=True) receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name, target_address=target_address) emitter.message(f"Successfully re-targeted {contract_name} proxy to {target_address}", color='green') paint_receipt_summary(emitter=emitter, receipt=receipt) else: if not actor_options.force: click.confirm(f"Confirm deploy new version of {contract_name} and retarget proxy?", abort=True) receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name, ignore_deployed=ignore_deployed) emitter.message(f"Successfully deployed and upgraded {contract_name}", color='green') for name, receipt in receipts.items(): paint_receipt_summary(emitter=emitter, receipt=receipt)
def burn_unclaimed_tokens(general_config, registry_options, checksum_address): emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry) if not checksum_address: checksum_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) receipt = worklock_agent.burn_unclaimed(sender_address=checksum_address) paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=worklock_agent.blockchain.client.chain_name) return # Exit
def remaining_work(general_config, worklock_options, registry_options): emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry) _remaining_work = bidder.remaining_work emitter.message(f"Work Remaining for {worklock_options.bidder_address}: {_remaining_work}") return # Exit
def create_actor(self, emitter, is_multisig: bool = False): _ensure_config_root(self.config_root) deployer_interface = _initialize_blockchain(poa=self.poa, provider_uri=self.provider_uri, emitter=emitter, ignore_solidity_check=self.ignore_solidity_check, gas_strategy=self.gas_strategy) # Warnings _pre_launch_warnings(emitter, self.etherscan, self.hw_wallet) # # Establish Registry # local_registry = establish_deployer_registry(emitter=emitter, use_existing_registry=bool(self.contract_name), registry_infile=self.registry_infile, registry_outfile=self.registry_outfile, dev=self.dev) # # Make Authenticated Deployment Actor # # Verify Address & collect password password = None if is_multisig: multisig_agent = ContractAgency.get_agent(MultiSigAgent, registry=local_registry) deployer_address = multisig_agent.contract.address is_transacting = False else: is_transacting = True deployer_address = self.deployer_address if not deployer_address: prompt = "Select deployer account" deployer_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, show_balances=False) if not self.force: click.confirm("Selected {} - Continue?".format(deployer_address), abort=True) if not self.hw_wallet and not deployer_interface.client.is_local: password = get_client_password(checksum_address=deployer_address) # Produce Actor ADMINISTRATOR = ContractAdministrator(registry=local_registry, client_password=password, deployer_address=deployer_address, is_transacting=is_transacting, staking_escrow_test_mode=self.se_test_mode) # Verify ETH Balance emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}") if is_transacting and ADMINISTRATOR.eth_balance == 0: emitter.echo("Deployer address has no ETH.", color='red', bold=True) raise click.Abort() return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
def enable_claiming(general_config, registry_options, worklock_options, force, hw_wallet, gas_limit): """Ensure correctness of bidding and enable claiming""" emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) if not worklock_options.bidder_address: # TODO: Consider bundle this in worklock_options worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=registry_options.provider_uri, network=registry_options.network, registry=registry, show_balances=True) bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) whales = bidder.get_whales() if whales: headers = ("Bidders that require correction", "Current bid bonus") columns = (whales.keys(), map(prettify_eth_amount, whales.values())) 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) force_refund_receipt = bidder.force_refund() emitter.echo(f"At least {len(whales)} bidders got a force refund\n", color='green') paint_receipt_summary(receipt=force_refund_receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name, transaction_type=f"force-refund") else: emitter.echo(f"All bids are correct, force refund is not needed\n", color='yellow') if not bidder.worklock_agent.bidders_checked(): if not gas_limit: # TODO print gas estimations min_gas = 180000 gas_limit = click.prompt(f"Enter gas limit per each verification transaction (at least {min_gas})", type=click.IntRange(min=min_gas)) if not force: click.confirm(f"Confirm verifying of bidding from {worklock_options.bidder_address} " f"using {gas_limit} gas per each transaction?", abort=True) verification_receipts = bidder.verify_bidding_correctness(gas_limit=gas_limit) emitter.echo("Bidding has been checked\n", color='green') for iteration, receipt in verification_receipts.items(): paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name, transaction_type=f"verify-correctness[{iteration}]") else: emitter.echo(f"Bidders have already been checked\n", color='yellow') return # Exit
def bid(general_config, worklock_options, registry_options, force, hw_wallet, value): """Place a bid, or increase an existing bid""" emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) 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_bidding_date: raise click.Abort(f"You can't bid, the bidding window is closed.") if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=registry_options.provider_uri, poa=registry_options.poa, network=registry_options.network, registry=registry, show_balances=True) bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) 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') prompt = f"Enter bid amount in ETH (at least {minimum_bid_in_eth} ETH)" else: # There's an existing bid and the bidder is increasing the amount emitter.message(f"You have an existing bid of {Web3.fromWei(existing_bid_amount, 'ether')} ETH") minimum_bid_in_eth = Web3.fromWei(1, 'ether') prompt = f"Enter the amount in ETH that you want to increase your bid" value = click.prompt(prompt, type=DecimalRange(min=minimum_bid_in_eth)) 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) 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' 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'Note that available claim value may fluctuate until bidding closes and claims are finalized.\n' emitter.echo(message, color='yellow') paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def refund(general_config, worklock_options, registry_options, force): emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) if not force: click.confirm(f"Collect ETH refund for bidder {worklock_options.bidder_address}?", abort=True) emitter.message("Submitting WorkLock refund request...") registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry) receipt = bidder.refund_deposit() paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def claim(general_config, worklock_options, registry_options, force, hw_wallet): """Claim tokens for your bid, and start staking them""" emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) 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=registry_options.provider_uri, poa=registry_options.poa, network=registry_options.network, registry=registry, show_balances=True) bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) unspent_bid = bidder.available_compensation if unspent_bid: emitter.echo(f"Note that WorkLock did not use your entire bid due to a maximum claim limit.\n" f"Therefore, an unspent amount of {prettify_eth_amount(unspent_bid)} is available for refund.") if not force: click.confirm(f"Before claiming your NU tokens for {worklock_options.bidder_address}, you will need to be refunded your unspent bid amount. Would you like to proceed?", abort=True) emitter.echo("Requesting refund of unspent bid amount...") receipt = bidder.withdraw_compensation() paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) has_claimed = bidder._has_claimed if has_claimed: emitter.echo(f"Claim was already done for {bidder.checksum_address}", color='red') return tokens = NU.from_nunits(bidder.available_claim) emitter.echo(f"\nYou have an available claim of {tokens} 🎉 \n", color='green', bold=True) if not force: lock_duration = bidder.worklock_agent.worklock_parameters()[-2] emitter.echo(f"Note: Claiming WorkLock NU tokens will initialize a new stake to be locked for {lock_duration} periods.", color='blue') click.confirm(f"Continue WorkLock claim for bidder {worklock_options.bidder_address}?", abort=True) emitter.echo("Submitting 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, network=registry_options.network, provider_uri=registry_options.provider_uri) return # Exit
def cancel_bid(general_config, registry_options, worklock_options, force): emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry) if not force: value = bidder.get_deposited_eth click.confirm(f"Confirm bid cancellation of {Web3.fromWei(value, 'ether')} ETH" f" for {worklock_options.bidder_address}?", abort=True) receipt = bidder.cancel_bid() paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def claim(general_config, worklock_options, registry_options, force): emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) if not force: emitter.message("Note: Claiming WorkLock NU tokens will initialize a new stake.", color='blue') click.confirm(f"Continue worklock claim for bidder {worklock_options.bidder_address}?", abort=True) emitter.message("Submitting Claim...") registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry) receipt = bidder.claim() paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) paint_worklock_claim(emitter, bidder_address=worklock_options.bidder_address) return # Exit
def remaining_work(general_config, worklock_options, registry_options): emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account( emitter=emitter, provider_uri=registry_options.provider_uri, network=registry_options.network, show_balances=True) registry = registry_options.get_registry(emitter, general_config.debug) 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}" ) return # Exit
def bid(general_config, worklock_options, registry_options, force, hw_wallet, value): """Place a bid""" emitter = _setup_emitter(general_config) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account( emitter=emitter, provider_uri=registry_options.provider_uri, network=registry_options.network, show_balances=True) if not value: if force: raise click.MissingParameter("Missing --value.") value = click.prompt("Enter bid amount in ETH", type=click.STRING) value = int(Web3.toWei(Decimal(value), 'ether')) registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet) if not force: paint_bidding_notice(emitter=emitter, bidder=bidder) click.confirm(f"Place WorkLock bid of {prettify_eth_amount(value)}?", abort=True) receipt = bidder.place_bid(value=value) emitter.message("Publishing WorkLock Bid...") # Ensure the total bid value is worth a claim that is at # least large enough for the minimum stake. minimum = bidder.economics.minimum_allowed_locked available_claim = NU.from_nunits(bidder.available_claim) if available_claim < minimum: warning = f"Total bid ({available_claim}) is too small for a claim, please bid more or cancel.\n" \ f"Total must be worth at least {NU.from_nunits(minimum)})." emitter.echo(warning, color='yellow') else: message = f'Current bid: {prettify_eth_amount(bidder.get_deposited_eth)} | ' \ f'Available claim: {available_claim}\n' \ f'Note that available claim value may fluctuate until bidding closes and claims are finalized.\n' emitter.echo(message, color='yellow') paint_receipt_summary( receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit
def execute(general_config, blockchain_options, multisig_options, proposal): """ Collect authorizations from executives and execute transaction through MultiSig contract """ # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = blockchain_options.get_registry() proposal = Proposal.from_file(proposal) if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account( emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) name, version, address, abi = registry.search( contract_address=proposal.target_address) # TODO: This assumes that we're always signing proxy retargetting. For the moment is true. proxy_contract = blockchain.client.w3.eth.contract( abi=abi, address=address, version=version, ContractFactoryClass=blockchain._contract_factory) paint_multisig_proposed_transaction(emitter, proposal, proxy_contract) trustee = multisig_options.create_trustee(registry) threshold = trustee.multisig_agent.threshold while len(trustee.authorizations) < threshold: auth_hex = click.prompt("Signature", type=click.STRING) authorization = Authorization.from_hex(auth_hex) executive_address = trustee.add_authorization(authorization, proposal) emitter.echo(f"Added authorization from executive {executive_address}", color='green') click.confirm( "\nCollected required authorizations. Proceed with execution?", abort=True) receipt = trustee.execute(proposal) paint_receipt_summary(emitter, receipt)
def remaining_work(general_config, worklock_options, registry_options): """Check how much work is pending until you can get all your locked ETH back""" emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=registry_options.provider_uri, poa=registry_options.poa, network=registry_options.network, registry=registry, show_balances=True) 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}") return # Exit
def generate_config(self, emitter, config_root, federated_only): checksum_address = self.checksum_address if not checksum_address and not federated_only: checksum_address = select_client_account( emitter=emitter, provider_uri=self.provider_uri, show_balances=False) return BobConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, checksum_address=checksum_address, domains=self.domains, federated_only=federated_only, registry_filepath=self.registry_filepath, provider_uri=self.provider_uri)
def propose(general_config, blockchain_options, multisig_options): """ Create a proposal of MultiSig transaction """ # TODO: Extend this command to cover this list of proposals # - Add new MultiSig owner # - Remove MultiSig owner # - Change threshold of MultiSig # - Upgrade contract (in particular, retarget to a deployed one) # - Transfer ownership of contract # - Send ETH from MultiSig # - Send tokens from MultiSig # - Change min reward rate range in PolicyManager # - Send raw transaction # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = blockchain_options.get_registry() if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account( emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) trustee = multisig_options.create_transactingless_trustee(registry) # As a PoC, this command only allows to change the threshold # TODO: Think in the UX for choosing between different types of proposals new_threshold = click.prompt("New threshold", type=click.INT) proposal = trustee.propose_changing_threshold(new_threshold) paint_multisig_proposed_transaction(emitter=emitter, proposal=proposal, registry=registry) filepath = f'proposal-changeThreshold-{trustee.multisig_agent.contract_address[:8]}-TX-{proposal.nonce}.json' proposal.write(filepath=filepath) emitter.echo(f"✅ Saved proposal to {filepath}", color='blue', bold=True)
def burn_unclaimed_tokens(general_config, registry_options, checksum_address): emitter = _setup_emitter(general_config) registry = registry_options.get_registry(emitter, general_config.debug) worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry) if not checksum_address: checksum_address = select_client_account( emitter=emitter, provider_uri=registry_options.provider_uri, network=registry_options.network, show_balances=True) # FIXME: This won't work in real life, it needs TransactingPowers and stuff receipt = worklock_agent.burn_unclaimed(sender_address=checksum_address) paint_receipt_summary( receipt=receipt, emitter=emitter, chain_name=worklock_agent.blockchain.client.chain_name) return # Exit
def sign(general_config, blockchain_options, multisig_options, proposal): """ Sign a proposed transaction before being sent to the MultiSig contract for execution """ # Init emitter = general_config.emitter #_ensure_config_root(actor_options.config_root) blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug) registry = blockchain_options.get_registry() proposal = Proposal.from_file(proposal) if not multisig_options.checksum_address: multisig_options.checksum_address = select_client_account( emitter=emitter, provider_uri=blockchain_options.provider_uri, poa=blockchain_options.poa, network=blockchain_options.network, registry=registry, show_balances=True) name, version, address, abi = registry.search( contract_address=proposal.target_address) # TODO: This assumes that we're always signing proxy retargetting. For the moment is true. proxy_contract = blockchain.client.w3.eth.contract( abi=abi, address=address, version=version, ContractFactoryClass=blockchain._contract_factory) paint_multisig_proposed_transaction(emitter, proposal, proxy_contract) click.confirm("Proceed with signing?", abort=True) executive = multisig_options.create_transactingless_executive( registry) # FIXME: Since we use a signer, don't ask for PW authorization = executive.authorize_proposal(proposal) emitter.echo( f"\nSignature received from {authorization.recover_executive_address(proposal)}:\n" ) emitter.echo(f"{authorization.serialize().hex()}\n", bold=True, color='green')
def _make_authenticated_deployment_actor(emitter, provider_uri, deployer_address, deployer_interface, contract_name, registry_infile, registry_outfile, hw_wallet, dev, force, se_test_mode): # # Establish Registry # local_registry = establish_deployer_registry( emitter=emitter, use_existing_registry=bool(contract_name), registry_infile=registry_infile, registry_outfile=registry_outfile, dev=dev) # # Make Authenticated Deployment Actor # # Verify Address & collect password if not deployer_address: prompt = "Select deployer account" deployer_address = select_client_account(emitter=emitter, prompt=prompt, provider_uri=provider_uri, show_balances=False) if not force: click.confirm("Selected {} - Continue?".format(deployer_address), abort=True) password = None if not hw_wallet and not deployer_interface.client.is_local: password = get_client_password(checksum_address=deployer_address) # Produce Actor ADMINISTRATOR = ContractAdministrator( registry=local_registry, client_password=password, deployer_address=deployer_address, staking_escrow_test_mode=se_test_mode) # Verify ETH Balance emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}") if ADMINISTRATOR.eth_balance == 0: emitter.echo("Deployer address has no ETH.", color='red', bold=True) raise click.Abort() return ADMINISTRATOR, deployer_address, local_registry
def generate_config(self, emitter, config_root, force): assert not self.dev # TODO: Raise instead worker_address = self.worker_address if (not worker_address) and not self.federated_only: if not worker_address: prompt = "Select worker account" worker_address = select_client_account( emitter=emitter, prompt=prompt, provider_uri=self.provider_uri, show_balances=False) rest_host = self.rest_host if not rest_host: rest_host = os.environ.get(NUCYPHER_ENVVAR_WORKER_IP_ADDRESS) if not rest_host: # TODO: Something less centralized... :-( # TODO: Ask Ursulas instead rest_host = actions.determine_external_ip_address(emitter, force=force) return UrsulaConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=self.rest_port, db_filepath=self.db_filepath, domains=self.domains, federated_only=self.federated_only, worker_address=worker_address, registry_filepath=self.registry_filepath, provider_process=self.eth_node, provider_uri=self.provider_uri, signer_uri=self.signer_uri, gas_strategy=self.gas_strategy, poa=self.poa, light=self.light, availability_check=self.availability_check)
def bid(general_config, worklock_options, registry_options, force, value): emitter = _setup_emitter(general_config) if not value: if force: raise click.MissingParameter("Missing --value.") value = int(Web3.fromWei(click.prompt("Enter bid amount in ETH", type=click.FloatRange(min=0)), 'wei')) if not worklock_options.bidder_address: worklock_options.bidder_address = select_client_account(emitter=emitter, provider_uri=general_config.provider_uri) registry = registry_options.get_registry(emitter, general_config.debug) bidder = worklock_options.create_bidder(registry=registry) if not force: paint_bidding_notice(emitter=emitter, bidder=bidder) click.confirm(f"Place WorkLock bid of {Web3.fromWei(value, 'ether')} ETH?", abort=True) receipt = bidder.place_bid(value=value) emitter.message("Publishing WorkLock Bid...") # Ensure the total bid value is worth a claim that is at # least large enough for the minimum stake. minimum = bidder.economics.minimum_allowed_locked available_claim = bidder.available_claim if available_claim < minimum: warning = f"Total bid is too small for a claim, please bid more or cancel. " \ f"{available_claim} total / {minimum} minimum" \ f"(Total must be worth at least {NU.from_nunits(minimum)})" emitter.echo(warning, color='yellow') else: message = f'Current bid: {bidder.get_deposited_eth} | ' \ f'Available Claim: {bidder.available_claim} |' \ f'Note that available claim value may fluctuate ' \ f'until bidding closes and claims are finalized.' emitter.echo(message, color='yellow') paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name) return # Exit