Example #1
0
def transfer_tokens(general_config, actor_options, target_address, value):
    """Transfer tokens from contract's owner address to another address"""

    emitter = general_config.emitter
    ADMINISTRATOR, deployer_address, _, local_registry = actor_options.create_actor(
        emitter)

    token_agent = ContractAgency.get_agent(
        NucypherTokenAgent,
        registry=local_registry)  # type: NucypherTokenAgent
    tokens = NU.from_nunits(token_agent.get_balance(deployer_address))
    emitter.echo(
        DISPLAY_SENDER_TOKEN_BALANCE_BEFORE_TRANSFER.format(
            token_balance=tokens))
    if not target_address:
        target_address = click.prompt(PROMPT_RECIPIENT_CHECKSUM_ADDRESS,
                                      type=EIP55_CHECKSUM_ADDRESS)
    if not value:
        stake_value_range = click.FloatRange(min=0, clamp=False)
        value = NU.from_tokens(
            click.prompt(PROMPT_TOKEN_VALUE, type=stake_value_range))

    confirmation = CONFIRM_TOKEN_TRANSFER.format(
        value=value,
        deployer_address=deployer_address,
        target_address=target_address)
    click.confirm(confirmation, abort=True)
    receipt = token_agent.transfer(amount=int(value),
                                   sender_address=deployer_address,
                                   target_address=target_address)
    paint_receipt_summary(emitter=emitter, receipt=receipt)
Example #2
0
def commit_to_next_period(general_config, character_options, config_file):
    """Manually make a commitment to the next period."""

    # Setup
    emitter = setup_emitter(general_config,
                            character_options.config_options.worker_address)
    _pre_launch_warnings(emitter,
                         dev=character_options.config_options.dev,
                         force=None)
    _, URSULA = character_options.create_character(emitter,
                                                   config_file,
                                                   general_config.json_ipc,
                                                   load_seednodes=False)

    committed_period = URSULA.staking_agent.get_current_period() + 1
    click.echo(
        CONFIRMING_ACTIVITY_NOW.format(committed_period=committed_period),
        color='blue')
    receipt = URSULA.commit_to_next_period()

    economics = EconomicsFactory.get_economics(registry=URSULA.registry)
    date = datetime_at_period(period=committed_period,
                              seconds_per_period=economics.seconds_per_period)

    # TODO: Double-check dates here
    message = SUCCESSFUL_CONFIRM_ACTIVITY.format(
        committed_period=committed_period, date=date)
    emitter.echo(message, bold=True, color='blue')
    paint_receipt_summary(
        emitter=emitter,
        receipt=receipt,
        chain_name=URSULA.staking_agent.blockchain.client.chain_name)
Example #3
0
def transfer_ownership(general_config, actor_options, target_address, gas):
    """Transfer ownership of contracts to another address."""
    emitter = general_config.emitter
    ADMINISTRATOR, _, _, _ = actor_options.create_actor(emitter)

    if not target_address:
        target_address = click.prompt(PROMPT_NEW_OWNER_ADDRESS, type=EIP55_CHECKSUM_ADDRESS)

    contract_name = actor_options.contract_name
    if not contract_name:
        raise click.MissingParameter(param="--contract-name", message="You need to specify an ownable contract")

    try:
        contract_deployer_class = ADMINISTRATOR.deployers[contract_name]
    except KeyError:
        message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name,
                                               contracts=ADMINISTRATOR.ownable_deployer_classes.keys())
        emitter.echo(message, color='red', bold=True)
        raise click.Abort()

    if contract_deployer_class not in ADMINISTRATOR.ownable_deployer_classes:
        message = CONTRACT_IS_NOT_OWNABLE.format(contract_name=contract_name)
        emitter.echo(message, color='red', bold=True)
        raise click.Abort()

    contract_deployer = contract_deployer_class(registry=ADMINISTRATOR.registry,
                                                deployer_address=ADMINISTRATOR.deployer_address)
    receipt = contract_deployer.transfer_ownership(new_owner=target_address, transaction_gas_limit=gas)
    paint_receipt_summary(emitter=emitter, receipt=receipt)
Example #4
0
def set_min_rate(general_config, transacting_staker_options, config_file, force, min_rate):
    """Staker sets the minimum acceptable fee rate for their associated worker."""

    # 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)

    if not min_rate:
        paint_min_rate(emitter, STAKEHOLDER.registry, STAKEHOLDER.policy_agent, staking_address)
        # TODO check range
        min_rate = click.prompt(PROMPT_STAKER_MIN_POLICY_RATE, type=WEI)
    if not force:
        click.confirm(CONFIRM_NEW_MIN_POLICY_RATE.format(min_rate=min_rate), abort=True)
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)
    receipt = STAKEHOLDER.set_min_fee_rate(min_rate=min_rate)

    # Report Success
    message = SUCCESSFUL_SET_MIN_POLICY_RATE.format(min_rate=min_rate, staking_address=staking_address)
    emitter.echo(message, color='green')
    paint_receipt_summary(emitter=emitter,
                          receipt=receipt,
                          chain_name=blockchain.client.chain_name,
                          transaction_type='set_min_rate')
Example #5
0
def enable_claiming(general_config: GroupGeneralConfig,
                    worklock_options: WorkLockOptions,
                    force: bool,
                    hw_wallet: bool,
                    gas_limit: int):
    """Ensure correctness of WorkLock participants and enable allocation"""
    emitter, registry, blockchain = worklock_options.setup(general_config=general_config)
    bidder_address = worklock_options.get_bidder_address(emitter, registry)
    bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)

    whales = bidder.get_whales()
    if whales:
        headers = ("Participants that require correction", "Current 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)} participants using {bidder_address}?", abort=True)

        force_refund_receipt = bidder.force_refund()
        emitter.echo(WHALE_WARNING.format(number=len(whales)), 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(BIDS_VALID_NO_FORCE_REFUND_INDICATED, color='yellow')

    if not bidder.worklock_agent.bidders_checked():

        confirmation = gas_limit and force
        while not confirmation:
            if not gas_limit:
                min_gas = 180000
                gas_limit = click.prompt(PROMPT_BID_VERIFY_GAS_LIMIT.format(min_gas=min_gas), type=click.IntRange(min=min_gas))

            bidders_per_transaction = bidder.worklock_agent.estimate_verifying_correctness(gas_limit=gas_limit)

            if not force:
                message = CONFIRM_BID_VERIFICATION.format(bidder_address=bidder_address,
                                                          gas_limit=gas_limit,
                                                          bidders_per_transaction=bidders_per_transaction)
                confirmation = click.confirm(message)
                gas_limit = gas_limit if confirmation else None
            else:
                emitter.echo(VERIFICATION_ESTIMATES.format(gas_limit=gas_limit,
                                                           bidders_per_transaction=bidders_per_transaction))
                confirmation = True

        verification_receipts = bidder.verify_bidding_correctness(gas_limit=gas_limit)
        emitter.echo(COMPLETED_BID_VERIFICATION, 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(BIDDERS_ALREADY_VERIFIED, color='yellow')
Example #6
0
def cancel_escrow(general_config: GroupGeneralConfig,
                  worklock_options: WorkLockOptions, force: bool,
                  hw_wallet: bool):
    """Cancel your escrow 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:
        emitter.echo(CANCELLATION_WINDOW_CLOSED, 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)
    if not force:
        value = bidder.get_deposited_eth
        click.confirm(
            f"Confirm escrow 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)
    return  # Exit
Example #7
0
def rollback(general_config, actor_options):
    """Rollback a proxy contract's target."""
    emitter = general_config.emitter
    ADMINISTRATOR, _, _, _ = actor_options.create_actor(emitter)
    if not actor_options.contract_name:
        raise click.BadArgumentUsage(message="--contract-name is required when using --rollback")
    receipt = ADMINISTRATOR.rollback_contract(contract_name=actor_options.contract_name)
    paint_receipt_summary(emitter=emitter, receipt=receipt)
Example #8
0
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 = 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)

    # Handle stake update and selection
    if index is not None:  # 0 is valid.
        current_stake = STAKEHOLDER.stakes[index]
    else:
        current_stake = select_stake(staker=STAKEHOLDER, emitter=emitter)

    #
    # Prolong
    #

    # Interactive
    if not lock_periods:
        max_extension = MAX_UINT16 - current_stake.final_locked_period
        # +1 because current period excluded
        min_extension = economics.minimum_locked_periods - current_stake.periods_remaining + 1
        if min_extension < 1:
            min_extension = 1
        duration_extension_range = click.IntRange(min=min_extension, max=max_extension, clamp=False)
        lock_periods = click.prompt(PROMPT_PROLONG_VALUE.format(minimum=min_extension, maximum=max_extension),
                                    type=duration_extension_range)
    if not force:
        click.confirm(CONFIRM_PROLONG.format(lock_periods=lock_periods), abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)

    # 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(PERIOD_ADVANCED_WARNING, color='red')
        raise click.Abort

    # Execute
    receipt = STAKEHOLDER.prolong_stake(stake=current_stake, additional_periods=lock_periods)

    # Report
    emitter.echo(SUCCESSFUL_STAKE_PROLONG, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
    paint_stakes(emitter=emitter, staker=STAKEHOLDER)
Example #9
0
def merge(general_config, transacting_staker_options, config_file, force, index_1, index_2):
    """Merge two stakes into one."""

    # 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()

    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)

    # Handle stakes selection
    stake_1, stake_2 = None, None

    if index_1 is not None and index_2 is not None:
        stake_1 = STAKEHOLDER.stakes[index_1]
        stake_2 = STAKEHOLDER.stakes[index_2]
    elif index_1 is not None:  # 0 is valid.
        stake_1 = STAKEHOLDER.stakes[index_1]
    elif index_2 is not None:
        stake_1 = STAKEHOLDER.stakes[index_2]

    if stake_1 is None:
        stake_1 = select_stake(staker=STAKEHOLDER, emitter=emitter)
    if stake_2 is None:
        emitter.echo(ONLY_DISPLAYING_MERGEABLE_STAKES_NOTE.format(final_period=stake_1.final_locked_period),
                     color='yellow')
        stake_2 = select_stake(staker=STAKEHOLDER,
                               emitter=emitter,
                               filter_function=lambda s: s.index != stake_1.index and
                                                         s.final_locked_period == stake_1.final_locked_period)

    if not force:
        click.confirm(CONFIRM_MERGE.format(stake_index_1=stake_1.index, stake_index_2=stake_2.index), abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)

    # 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(PERIOD_ADVANCED_WARNING, color='red')
        raise click.Abort

    # Execute
    receipt = STAKEHOLDER.merge_stakes(stake_1=stake_1, stake_2=stake_2)

    # Report
    emitter.echo(SUCCESSFUL_STAKES_MERGE, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter, receipt=receipt, chain_name=blockchain.client.chain_name)
    paint_stakes(emitter=emitter, staker=STAKEHOLDER)
Example #10
0
def restake(general_config, transacting_staker_options, config_file, enable,
            lock_until, force):
    """Manage re-staking 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)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)
    STAKEHOLDER.assimilate(checksum_address=client_account, password=password)

    # Inner Exclusive Switch
    if lock_until:
        if not force:
            confirm_enable_restaking_lock(emitter,
                                          staking_address=staking_address,
                                          release_period=lock_until)
        receipt = STAKEHOLDER.enable_restaking_lock(release_period=lock_until)
        emitter.echo(SUCCESSFUL_ENABLE_RESTAKE_LOCK.format(
            staking_address=staking_address, lock_until=lock_until),
                     color='green',
                     verbosity=1)
    elif enable:
        if not force:
            confirm_enable_restaking(emitter, staking_address=staking_address)
        receipt = STAKEHOLDER.enable_restaking()
        emitter.echo(SUCCESSFUL_ENABLE_RESTAKING.format(
            staking_address=staking_address),
                     color='green',
                     verbosity=1)
    else:
        if not force:
            click.confirm(CONFIRM_DISABLE_RESTAKING.format(
                staking_address=staking_address),
                          abort=True)
        receipt = STAKEHOLDER.disable_restaking()
        emitter.echo(SUCCESSFUL_DISABLE_RESTAKING.format(
            staking_address=staking_address),
                     color='green',
                     verbosity=1)

    paint_receipt_summary(receipt=receipt,
                          emitter=emitter,
                          chain_name=blockchain.client.chain_name)
Example #11
0
def escrow(general_config: GroupGeneralConfig,
           worklock_options: WorkLockOptions,
           force: bool,
           hw_wallet: bool,
           value: Decimal):
    """Create an ETH escrow, or increase an existing escrow"""
    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_bidding_date:
        emitter.echo(BIDDING_WINDOW_CLOSED, 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)

    existing_bid_amount = bidder.get_deposited_eth
    if not value:
        if force:
            raise click.MissingParameter("Missing --value.")

        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 = BID_AMOUNT_PROMPT_WITH_MIN_BID.format(minimum_bid_in_eth=minimum_bid_in_eth)
        else:  # There's an existing bid and the bidder is increasing the amount
            emitter.message(EXISTING_BID_AMOUNT_NOTICE.format(eth_amount=Web3.fromWei(existing_bid_amount, 'ether')))
            minimum_bid_in_eth = Web3.fromWei(1, 'ether')
            prompt = BID_INCREASE_AMOUNT_PROMPT
        value = click.prompt(prompt, type=DecimalRange(min=minimum_bid_in_eth))

    value = int(Web3.toWei(Decimal(value), 'ether'))

    if not force:
        if not existing_bid_amount:
            paint_bidding_notice(emitter=emitter, bidder=bidder)
            click.confirm(f"Place WorkLock escrow of {prettify_eth_amount(value)}?", abort=True)
        else:
            click.confirm(f"Increase current escrow ({prettify_eth_amount(existing_bid_amount)}) "
                          f"by {prettify_eth_amount(value)}?", abort=True)

    receipt = bidder.place_bid(value=value)
    emitter.message("Publishing WorkLock Escrow...")

    maximum = NU.from_nunits(bidder.economics.maximum_allowed_locked)
    available_claim = NU.from_nunits(bidder.available_claim)
    message = f'\nCurrent escrow: {prettify_eth_amount(bidder.get_deposited_eth)} | Allocation: {available_claim}\n'
    if available_claim > maximum:
        message += f"\nThis allocation is currently above the allowed max ({maximum}), " \
                   f"so the escrow may be partially refunded.\n"
    message += f'Note that the available allocation value may fluctuate until the escrow period closes and ' \
               f'allocations are finalized.\n'
    emitter.echo(message, color='yellow')

    paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name)
Example #12
0
def paint_staking_confirmation(emitter, staker, receipt):
    emitter.echo("\nStake initialization transaction was successful.",
                 color='green')
    emitter.echo(f'\nTransaction details:')
    paint_receipt_summary(emitter=emitter,
                          receipt=receipt,
                          transaction_type="deposit stake")
    emitter.echo(
        f'\n{STAKING_ESCROW_CONTRACT_NAME} address: {staker.staking_agent.contract_address}',
        color='blue')
    emitter.echo(POST_STAKING_ADVICE, color='green')
Example #13
0
def winddown(general_config, transacting_staker_options, config_file, enable,
             force):
    """Manage winding down 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:
            confirm_enable_winding_down(emitter,
                                        staking_address=staking_address)

        # Authenticate and Execute
        password = transacting_staker_options.get_password(
            blockchain, client_account)
        STAKEHOLDER.assimilate(password=password)

        receipt = STAKEHOLDER.enable_winding_down()
        emitter.echo(SUCCESSFUL_ENABLE_WIND_DOWN.format(
            staking_address=staking_address),
                     color='green',
                     verbosity=1)
    else:
        if not force:
            click.confirm(CONFIRM_DISABLE_WIND_DOWN.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.disable_winding_down()
        emitter.echo(SUCCESSFUL_DISABLE_WIND_DOWN.format(
            staking_address=staking_address),
                     color='green',
                     verbosity=1)

    paint_receipt_summary(receipt=receipt,
                          emitter=emitter,
                          chain_name=blockchain.client.chain_name)
Example #14
0
def unbond(registry_filepath, eth_provider_uri, signer_uri, staking_provider,
           network, force):
    """Unbonds an operator from an authorized staking provider."""

    #
    # Setup
    #

    emitter = StdoutEmitter()
    if not signer_uri:
        emitter.message('--signer is required', color='red')
        raise click.Abort()
    if not network:
        network = select_network(emitter=emitter,
                                 network_type=NetworksInventory.ETH)

    connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter)
    registry = get_registry(network=network,
                            registry_filepath=registry_filepath)
    agent = ContractAgency.get_agent(PREApplicationAgent, registry=registry)
    signer = Signer.from_signer_uri(signer_uri)
    transacting_power = TransactingPower(account=staking_provider,
                                         signer=signer)

    #
    # Check
    #

    bonded, onchain_operator_address = is_bonded(
        agent=agent, staking_provider=staking_provider, return_address=True)
    if not bonded:
        emitter.message(NOT_BONDED.format(provider=staking_provider),
                        color='red')
        raise click.Abort()
    check_bonding_requirements(emitter=emitter,
                               agent=agent,
                               staking_provider=staking_provider)

    #
    # Unbond
    #

    if not force:
        click.confirm(CONFIRM_UNBONDING.format(
            provider=staking_provider, operator=onchain_operator_address),
                      abort=True)
    transacting_power.unlock(password=get_client_password(
        checksum_address=staking_provider,
        envvar=NUCYPHER_ENVVAR_STAKING_PROVIDER_ETH_PASSWORD))
    emitter.echo(UNBONDING.format(operator=onchain_operator_address))
    receipt = agent.bond_operator(operator=NULL_ADDRESS,
                                  transacting_power=transacting_power,
                                  staking_provider=staking_provider)
    paint_receipt_summary(receipt=receipt, emitter=emitter)
Example #15
0
def bond_worker(general_config, transacting_staker_options, config_file, force, worker_address):
    """Bond a worker to a staker."""

    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()
    economics = STAKEHOLDER.economics

    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)

    if not worker_address:
        worker_address = click.prompt(PROMPT_WORKER_ADDRESS, type=EIP55_CHECKSUM_ADDRESS)

    if (worker_address == staking_address) and not force:
        click.confirm(CONFIRM_WORKER_AND_STAKER_ADDRESSES_ARE_EQUAL.format(address=worker_address), abort=True)

    # TODO: Check preconditions (e.g., minWorkerPeriods, already in use, etc)

    # TODO: Double-check dates
    # Calculate release datetime
    current_period = STAKEHOLDER.staking_agent.get_current_period()
    bonded_date = datetime_at_period(period=current_period, seconds_per_period=economics.seconds_per_period)
    min_worker_periods = STAKEHOLDER.economics.minimum_worker_periods

    release_period = current_period + min_worker_periods
    release_date = datetime_at_period(period=release_period,
                                      seconds_per_period=economics.seconds_per_period,
                                      start_of_period=True)

    if not force:
        click.confirm(f"Commit to bonding "
                      f"worker {worker_address} to staker {staking_address} "
                      f"for a minimum of {STAKEHOLDER.economics.minimum_worker_periods} periods?", abort=True)

    password = transacting_staker_options.get_password(blockchain, client_account)
    STAKEHOLDER.assimilate(password=password)
    receipt = STAKEHOLDER.bond_worker(worker_address=worker_address)

    # Report Success
    message = SUCCESSFUL_WORKER_BONDING.format(worker_address=worker_address, staking_address=staking_address)
    emitter.echo(message, color='green')
    paint_receipt_summary(emitter=emitter,
                          receipt=receipt,
                          chain_name=blockchain.client.chain_name,
                          transaction_type='bond_worker')
    emitter.echo(BONDING_DETAILS.format(current_period=current_period, bonded_date=bonded_date), color='green')
    emitter.echo(BONDING_RELEASE_INFO.format(release_period=release_period, release_date=release_date), color='green')
Example #16
0
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)
    bidder_address = worklock_options.get_bidder_address(emitter, registry)

    bidder = worklock_options.create_bidder(registry=registry, hw_wallet=hw_wallet)

    if not force:
        click.confirm(CONFIRM_COLLECT_WORKLOCK_REFUND.format(bidder_address=bidder_address), abort=True)
    emitter.echo(SUBMITTING_WORKLOCK_REFUND_REQUEST)

    receipt = bidder.refund_deposit()
    paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=bidder.staking_agent.blockchain.client.chain_name)
Example #17
0
def collect_reward(general_config, transacting_staker_options, config_file,
                   staking_reward, policy_fee, withdraw_address, force):
    """Withdraw staking reward."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()

    if not staking_reward and not policy_fee:
        raise click.BadArgumentUsage(
            f"Either --staking-reward or --policy-fee must be True to collect rewards."
        )

    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)

    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)

    STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
    if staking_reward:
        # Note: Sending staking / inflation rewards to another account is not allowed.
        reward_amount = NU.from_nunits(STAKEHOLDER.calculate_staking_reward())
        emitter.echo(message=COLLECTING_TOKEN_REWARD.format(
            reward_amount=reward_amount))
        staking_receipt = STAKEHOLDER.collect_staking_reward()
        paint_receipt_summary(
            receipt=staking_receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)

    if policy_fee:
        fee_amount = Web3.fromWei(STAKEHOLDER.calculate_policy_fee(), 'ether')
        emitter.echo(message=COLLECTING_ETH_REWARD.format(
            reward_amount=fee_amount))
        policy_receipt = STAKEHOLDER.collect_policy_fee(
            collector_address=withdraw_address)
        paint_receipt_summary(
            receipt=policy_receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)
Example #18
0
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 = get_registry(network=blockchain_options.network)

    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)  # FIXME: Unexpected argument!!

    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(PROMPT_FOR_RAW_SIGNATURE, type=click.STRING)
        authorization = Authorization.from_hex(auth_hex)
        executive_address = trustee.add_authorization(authorization, proposal)
        emitter.echo(SUCCESSFUL_MULTISIG_AUTHORIZATION.format(
            executive_address=executive_address),
                     color='green')

    click.confirm(CONFIRM_EXECUTE_MULTISIG_TRANSACTION, abort=True)

    receipt = trustee.execute(proposal)
    paint_receipt_summary(emitter, receipt)
Example #19
0
def preallocation(general_config, transacting_staker_options, config_file,
                  action, force):
    """Claim token rewards collected by a preallocation contract."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()

    # Unauthenticated actions: status
    if action == 'status':
        return paint_preallocation_status(
            emitter=emitter,
            token_agent=STAKEHOLDER.token_agent,
            preallocation_agent=STAKEHOLDER.preallocation_escrow_agent)

    # Authenticated actions: withdraw-tokens
    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)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)
    STAKEHOLDER.assimilate(checksum_address=client_account, password=password)

    if action == 'withdraw':
        token_balance = NU.from_nunits(
            STAKEHOLDER.token_agent.get_balance(staking_address))
        locked_tokens = NU.from_nunits(
            STAKEHOLDER.preallocation_escrow_agent.unvested_tokens)
        unlocked_tokens = token_balance - locked_tokens

        emitter.echo(message=COLLECTING_PREALLOCATION_REWARD.format(
            unlocked_tokens=unlocked_tokens, staking_address=staking_address))
        receipt = STAKEHOLDER.withdraw_preallocation_tokens(unlocked_tokens)
        paint_receipt_summary(
            receipt=receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)
Example #20
0
def unbond_worker(general_config, transacting_staker_options, config_file,
                  force):
    """
    Unbond worker currently bonded to a staker.
    """
    emitter = setup_emitter(general_config)

    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()

    economics = STAKEHOLDER.economics

    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)

    # TODO: Check preconditions (e.g., minWorkerPeriods)
    worker_address = STAKEHOLDER.staking_agent.get_worker_from_staker(
        staking_address)

    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)
    STAKEHOLDER.assimilate(password=password)
    receipt = STAKEHOLDER.unbond_worker()

    # TODO: Double-check dates
    current_period = STAKEHOLDER.staking_agent.get_current_period()
    bonded_date = datetime_at_period(
        period=current_period, seconds_per_period=economics.seconds_per_period)

    message = SUCCESSFUL_DETACH_WORKER.format(worker_address=worker_address,
                                              staking_address=staking_address)
    emitter.echo(message, color='green')
    paint_receipt_summary(emitter=emitter,
                          receipt=receipt,
                          chain_name=blockchain.client.chain_name,
                          transaction_type='unbond_worker')
    emitter.echo(DETACH_DETAILS.format(current_period=current_period,
                                       bonded_date=bonded_date),
                 color='green')
Example #21
0
def mint(general_config, transacting_staker_options, config_file, force):
    """Mint last portion of reward"""

    # 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)

    # Nothing to mint
    mintable_periods = STAKEHOLDER.mintable_periods()
    if mintable_periods == 0:
        emitter.echo(NO_MINTABLE_PERIODS, color='red')
        raise click.Abort

    # Still locked token
    if STAKEHOLDER.non_withdrawable_stake() > 0:
        emitter.echo(STILL_LOCKED_TOKENS, color='yellow')

    if not force:
        click.confirm(
            CONFIRM_MINTING.format(mintable_periods=mintable_periods),
            abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)
    STAKEHOLDER.assimilate(password=password)
    receipt = STAKEHOLDER.mint()
    emitter.echo(SUCCESSFUL_MINTING, color='green', verbosity=1)

    paint_receipt_summary(receipt=receipt,
                          emitter=emitter,
                          chain_name=blockchain.client.chain_name,
                          transaction_type='mint')
Example #22
0
def claim(general_config: GroupGeneralConfig, worklock_options: WorkLockOptions, force: bool, hw_wallet: bool):
    """Claim tokens for your escrow, 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():
        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=bidder_address)
            click.confirm(message, abort=True)
        emitter.echo(REQUESTING_WORKLOCK_COMPENSATION)
        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 bool(has_claimed):
        emitter.echo(CLAIM_ALREADY_PLACED.format(bidder_address=bidder.checksum_address), color='red')
        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=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=bidder_address,
                         network=worklock_options.network,
                         provider_uri=worklock_options.provider_uri)
Example #23
0
def paint_contract_deployment(emitter,
                              contract_name: str,
                              contract_address: str,
                              receipts: dict,
                              chain_name: str = None,
                              open_in_browser: bool = False):
    # TODO: switch to using an explicit emitter

    is_token_contract = contract_name == NUCYPHER_TOKEN_CONTRACT_NAME

    # Paint heading
    heading = f'\r{" "*80}\n{contract_name} ({contract_address})'
    emitter.echo(heading, bold=True)
    emitter.echo('*' * (42 + 3 + len(contract_name)))
    try:
        url = etherscan_url(item=contract_address,
                            network=chain_name,
                            is_token=is_token_contract)
    except ValueError as e:
        emitter.log.info("Failed Etherscan URL construction: " + str(e))
    else:
        emitter.echo(f" See {url}\n")

    # Paint Transactions
    for tx_name, receipt in receipts.items():
        paint_receipt_summary(emitter=emitter,
                              receipt=receipt,
                              chain_name=chain_name,
                              transaction_type=tx_name)

    if open_in_browser:
        try:
            url = etherscan_url(item=contract_address,
                                network=chain_name,
                                is_token=is_token_contract)
        except ValueError as e:
            emitter.log.info("Failed Etherscan URL construction: " + str(e))
        else:
            webbrowser.open_new_tab(url)
Example #24
0
def remove_inactive_substake(emitter, stakeholder: StakeHolder,
                             action_period: int, stake: Stake, chain_name: str,
                             force: bool) -> None:
    # Non-interactive: Consistency check to prevent the above agreement from going stale.
    last_second_current_period = stakeholder.staker.staking_agent.get_current_period(
    )
    if action_period != last_second_current_period:
        emitter.echo(PERIOD_ADVANCED_WARNING, color='red')
        raise click.Abort

    if not force:
        click.confirm(CONFIRM_REMOVE_SUBSTAKE.format(stake_index=stake.index),
                      abort=True)

    # Execute
    receipt = stakeholder.staker.remove_inactive_stake(stake=stake)

    # Report
    emitter.echo(SUCCESSFUL_STAKE_REMOVAL, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter,
                          receipt=receipt,
                          chain_name=chain_name)
    paint_stakes(emitter=emitter, staker=stakeholder.staker)
Example #25
0
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(CONFIRM_BUILD_RETARGET_TRANSACTION.format(
                contract_name=contract_name, target_address=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_eth_balance=False,
            show_nu_balance=False,
            show_staking=False)

        if not actor_options.force:
            click.confirm(
                CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address),
                abort=True)

        trustee = Trustee(registry=registry, checksum_address=trustee_address)
        transaction_proposal = trustee.create_transaction_proposal(transaction)

        message = SUCCESSFUL_RETARGET_TX_BUILT.format(
            contract_name=contract_name, target_address=target_address)
        emitter.message(message, 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(
            SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=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(CONFIRM_RETARGET.format(
                contract_name=contract_name, target_address=target_address),
                          abort=True)
        receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,
                                               target_address=target_address)
        message = SUCCESSFUL_RETARGET.format(contract_name=contract_name,
                                             target_address=target_address)
        emitter.message(message, color='green')
        paint_receipt_summary(emitter=emitter, receipt=receipt)
    else:
        if not actor_options.force:
            click.confirm(
                CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name),
                abort=True)
        receipts = ADMINISTRATOR.upgrade_contract(
            contract_name=contract_name, ignore_deployed=ignore_deployed)
        emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name),
                        color='green')
        for name, receipt in receipts.items():
            paint_receipt_summary(emitter=emitter, receipt=receipt)
Example #26
0
def contracts(general_config, actor_options, mode, activate, gas, ignore_deployed, confirmations, parameters):
    """Compile and deploy contracts."""

    emitter = general_config.emitter
    ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter)
    chain_name = deployer_interface.client.chain_name

    deployment_parameters = {}
    if parameters:
        with open(parameters) as json_file:
            deployment_parameters = json.load(json_file)

    contract_name = actor_options.contract_name
    deployment_mode = constants.__getattr__(mode.upper())  # TODO: constant sorrow
    try:
        contract_deployer_class = ADMINISTRATOR.deployers[contract_name]
    except KeyError:
        message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name,
                                               constants=ADMINISTRATOR.deployers.keys())
        emitter.echo(message, color='red', bold=True)
        raise click.Abort()

    if activate:
        # For the moment, only StakingEscrow can be activated
        staking_escrow_deployer = contract_deployer_class(registry=ADMINISTRATOR.registry,
                                                          deployer_address=ADMINISTRATOR.deployer_address)
        if contract_name != STAKING_ESCROW_CONTRACT_NAME or not staking_escrow_deployer.ready_to_activate:
            raise click.BadOptionUsage(option_name="--activate",
                                       message=f"You can only activate an idle instance of {STAKING_ESCROW_CONTRACT_NAME}")

        escrow_address = staking_escrow_deployer._get_deployed_contract().address
        prompt = CONFIRM_NETWORK_ACTIVATION.format(staking_escrow_name=STAKING_ESCROW_CONTRACT_NAME,
                                                   staking_escrow_address=escrow_address)
        click.confirm(prompt, abort=True)

        receipts = staking_escrow_deployer.activate(gas_limit=gas, confirmations=confirmations)
        for tx_name, receipt in receipts.items():
            paint_receipt_summary(emitter=emitter,
                                  receipt=receipt,
                                  chain_name=chain_name,
                                  transaction_type=tx_name)
        return  # Exit

    # Stage Deployment
    paint_staged_deployment(deployer_interface=deployer_interface, administrator=ADMINISTRATOR, emitter=emitter)

    # Confirm Trigger Deployment
    if not confirm_deployment(emitter=emitter, deployer_interface=deployer_interface):
        raise click.Abort()

    # Deploy
    emitter.echo(CONTRACT_DEPLOYMENT_SERIES_BEGIN_ADVISORY.format(contract_name=contract_name))
    receipts, agent = ADMINISTRATOR.deploy_contract(contract_name=contract_name,
                                                    gas_limit=gas,
                                                    deployment_mode=deployment_mode,
                                                    ignore_deployed=ignore_deployed,
                                                    confirmations=confirmations,
                                                    deployment_parameters=deployment_parameters)

    # Report
    paint_contract_deployment(contract_name=contract_name,
                              contract_address=agent.contract_address,
                              receipts=receipts,
                              emitter=emitter,
                              chain_name=chain_name,
                              open_in_browser=actor_options.etherscan)

    # Success
    registry_outfile = local_registry.filepath
    emitter.echo(SUCCESSFUL_REGISTRY_CREATION.format(registry_outfile=registry_outfile), bold=True, color='blue')
Example #27
0
def upgrade(general_config, actor_options, retarget, target_address, ignore_deployed, multisig, confirmations):
    """Upgrade NuCypher existing proxy contract deployments."""

    #
    # Setup
    #

    emitter = general_config.emitter
    ADMINISTRATOR, deployer_address, blockchain, local_registry = actor_options.create_actor(emitter, is_multisig=bool(multisig))  # FIXME: Workaround for building MultiSig TXs | NRN

    #
    # Pre-flight
    #

    contract_name = actor_options.contract_name
    if not contract_name:
        raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade")

    try:
        # Check contract name exists
        Deployer = ADMINISTRATOR.deployers[contract_name]
    except KeyError:
        message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name, constants=ADMINISTRATOR.deployers.keys())
        emitter.echo(message, color='red', bold=True)
        raise click.Abort()
    deployer = Deployer(registry=local_registry)

    # Check deployer address is owner
    if Deployer._ownable and deployer_address != deployer.owner:  # blockchain read
        emitter.echo(DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address,
                                                  contract_name=contract_name,
                                                  agent=deployer.make_agent()))
        raise click.Abort()
    else:
        emitter.echo('✓ Verified deployer address as contract owner', color='green')

    #
    # Business
    #

    if multisig:
        if not target_address:
            raise click.BadArgumentUsage(message="--multisig requires using --target-address.")
        if not actor_options.force:
            click.confirm(CONFIRM_BUILD_RETARGET_TRANSACTION.format(contract_name=contract_name,
                                                                    target_address=target_address), abort=True)
        transaction = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,
                                                   target_address=target_address,
                                                   just_build_transaction=True,
                                                   confirmations=confirmations)

        trustee_address = select_client_account(emitter=emitter,
                                                prompt="Select trustee address",
                                                provider_uri=actor_options.provider_uri,
                                                show_eth_balance=False,
                                                show_nu_balance=False,
                                                show_staking=False)

        if not actor_options.force:
            click.confirm(CONFIRM_SELECTED_ACCOUNT.format(address=trustee_address), abort=True)

        trustee = Trustee(registry=local_registry, checksum_address=trustee_address)
        transaction_proposal = trustee.create_transaction_proposal(transaction)

        message = SUCCESSFUL_RETARGET_TX_BUILT.format(contract_name=contract_name, target_address=target_address)
        emitter.message(message, 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(SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL.format(filepath=filepath), color='blue', bold=True)
        return  # Exit

    elif retarget:
        if not target_address:
            raise click.BadArgumentUsage(message="--target-address is required when using --retarget")
        if not actor_options.force:
            click.confirm(CONFIRM_RETARGET.format(contract_name=contract_name, target_address=target_address), abort=True)
        receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,target_address=target_address, confirmations=confirmations)
        message = SUCCESSFUL_RETARGET.format(contract_name=contract_name, target_address=target_address)
        emitter.message(message, color='green')
        paint_receipt_summary(emitter=emitter, receipt=receipt)
        return  # Exit

    else:
        github_registry = establish_deployer_registry(emitter=emitter,
                                                      download_registry=True,
                                                      network=actor_options.network)
        if not actor_options.force:

            # Check for human verification of versioned upgrade details
            click.confirm(CONFIRM_BEGIN_UPGRADE.format(contract_name=contract_name), abort=True)
            if deployer._ownable:  # Only ownable + upgradeable contracts apply
                verify_upgrade_details(blockchain=blockchain,
                                       registry=github_registry,
                                       deployer=deployer)

        # Success
        receipts = ADMINISTRATOR.upgrade_contract(contract_name=contract_name,
                                                  ignore_deployed=ignore_deployed,
                                                  confirmations=confirmations)
        emitter.message(SUCCESSFUL_UPGRADE.format(contract_name=contract_name), color='green')

        for name, receipt in receipts.items():
            paint_receipt_summary(emitter=emitter, receipt=receipt)
        emitter.echo(REGISTRY_PUBLICATION_HINT.format(contract_name=contract_name,
                                                      local_registry=local_registry,
                                                      network=actor_options.network), color='blue')
        emitter.echo(ETHERSCAN_VERIFY_HINT.format(solc_version=SOLIDITY_COMPILER_VERSION), color='blue')
        return  # Exit
Example #28
0
def contracts(general_config, actor_options, mode, activate, gas,
              ignore_deployed, confirmations, parameters):
    """Compile and deploy contracts."""

    emitter = general_config.emitter
    ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(
        emitter)
    chain_name = deployer_interface.client.chain_name

    deployment_parameters = {}
    if parameters:
        with open(parameters) as json_file:
            deployment_parameters = json.load(json_file)

    #
    # Deploy Single Contract (Amend Registry)
    #
    contract_name = actor_options.contract_name
    deployment_mode = constants.__getattr__(
        mode.upper())  # TODO: constant sorrow
    if contract_name:  # TODO: Remove this conditional, make it the default
        try:
            contract_deployer_class = ADMINISTRATOR.deployers[contract_name]
        except KeyError:
            message = UNKNOWN_CONTRACT_NAME.format(
                contract_name=contract_name,
                constants=ADMINISTRATOR.deployers.keys())
            emitter.echo(message, color='red', bold=True)
            raise click.Abort()

        if activate:
            # For the moment, only StakingEscrow can be activated
            staking_escrow_deployer = contract_deployer_class(
                registry=ADMINISTRATOR.registry,
                deployer_address=ADMINISTRATOR.deployer_address)
            if contract_name != STAKING_ESCROW_CONTRACT_NAME or not staking_escrow_deployer.ready_to_activate:
                raise click.BadOptionUsage(
                    option_name="--activate",
                    message=
                    f"You can only activate an idle instance of {STAKING_ESCROW_CONTRACT_NAME}"
                )

            escrow_address = staking_escrow_deployer._get_deployed_contract(
            ).address
            prompt = CONFIRM_NETWORK_ACTIVATION.format(
                staking_escrow_name=STAKING_ESCROW_CONTRACT_NAME,
                staking_escrow_address=escrow_address)
            click.confirm(prompt, abort=True)

            receipts = staking_escrow_deployer.activate(
                gas_limit=gas, confirmations=confirmations)
            for tx_name, receipt in receipts.items():
                paint_receipt_summary(emitter=emitter,
                                      receipt=receipt,
                                      chain_name=chain_name,
                                      transaction_type=tx_name)
            return  # Exit

        # Deploy
        emitter.echo(
            CONTRACT_DEPLOYMENT_SERIES_BEGIN_ADVISORY.format(
                contract_name=contract_name))
        receipts, agent = ADMINISTRATOR.deploy_contract(
            contract_name=contract_name,
            gas_limit=gas,
            deployment_mode=deployment_mode,
            ignore_deployed=ignore_deployed,
            confirmations=confirmations,
            deployment_parameters=deployment_parameters)

        # Report
        paint_contract_deployment(contract_name=contract_name,
                                  contract_address=agent.contract_address,
                                  receipts=receipts,
                                  emitter=emitter,
                                  chain_name=chain_name,
                                  open_in_browser=actor_options.etherscan)
        return  # Exit

    #
    # Deploy Automated Series (Create Registry)
    #
    if deployment_mode is not FULL:
        raise click.BadOptionUsage(
            option_name='--mode',
            message=
            "Only 'full' mode is supported when deploying all network contracts"
        )

    # Confirm filesystem registry writes.
    if os.path.isfile(local_registry.filepath):
        emitter.echo(EXISTING_REGISTRY_FOR_DOMAIN.format(
            registry_filepath=local_registry.filepath),
                     color='yellow')
        click.confirm(CONFIRM_LOCAL_REGISTRY_DESTRUCTION, abort=True)
        os.remove(local_registry.filepath)

    # Stage Deployment
    paint_staged_deployment(deployer_interface=deployer_interface,
                            administrator=ADMINISTRATOR,
                            emitter=emitter)

    # Confirm Trigger Deployment
    if not confirm_deployment(emitter=emitter,
                              deployer_interface=deployer_interface):
        raise click.Abort()

    # Delay - Last chance to abort via KeyboardInterrupt
    paint_deployment_delay(emitter=emitter)

    # Execute Deployment
    deployment_receipts = ADMINISTRATOR.deploy_network_contracts(
        emitter=emitter,
        interactive=not actor_options.force,
        etherscan=actor_options.etherscan,
        ignore_deployed=ignore_deployed)

    # Paint outfile paths
    registry_outfile = local_registry.filepath
    emitter.echo(
        SUCCESSFUL_REGISTRY_CREATION.format(registry_outfile=registry_outfile),
        bold=True,
        color='blue')

    # Save transaction metadata
    receipts_filepath = ADMINISTRATOR.save_deployment_receipts(
        receipts=deployment_receipts)
    emitter.echo(SUCCESSFUL_SAVE_DEPLOY_RECEIPTS.format(
        receipts_filepath=receipts_filepath),
                 color='blue',
                 bold=True)
Example #29
0
def divide(general_config, transacting_staker_options, config_file, force,
           value, lock_periods, index):
    """Create a new stake from part of an existing one."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()
    economics = STAKEHOLDER.economics
    action_period = STAKEHOLDER.staking_agent.get_current_period()

    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)

    # 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)

    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,
                                     divisible=True,
                                     staker_address=client_account)

    #
    # Stage Stake
    #

    # Value
    if not value:
        min_allowed_locked = NU.from_nunits(
            STAKEHOLDER.economics.minimum_allowed_locked)
        max_divide_value = max(min_allowed_locked,
                               current_stake.value - min_allowed_locked)
        prompt = PROMPT_STAKE_DIVIDE_VALUE.format(
            minimm=min_allowed_locked, maximum=str(max_divide_value))
        value = click.prompt(prompt, type=stake_value_range)
    value = NU(value, 'NU')

    # Duration
    if not lock_periods:
        max_extension = MAX_UINT16 - current_stake.final_locked_period
        divide_extension_range = click.IntRange(min=1,
                                                max=max_extension,
                                                clamp=False)
        extension = click.prompt(PROMPT_STAKE_EXTEND_VALUE,
                                 type=divide_extension_range)
    else:
        extension = lock_periods

    if not force:
        confirm_large_stake(lock_periods=extension, value=value)
        paint_staged_stake_division(emitter=emitter,
                                    stakeholder=STAKEHOLDER,
                                    original_stake=current_stake,
                                    target_value=value,
                                    extension=extension)
        click.confirm(CONFIRM_BROADCAST_STAKE_DIVIDE, abort=True)

    # Authenticate
    password = transacting_staker_options.get_password(blockchain,
                                                       client_account)

    # 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(PERIOD_ADVANCED_WARNING, red='red')
        raise click.Abort

    # Execute
    STAKEHOLDER.assimilate(checksum_address=current_stake.staker_address,
                           password=password)
    modified_stake, new_stake = STAKEHOLDER.divide_stake(
        stake_index=current_stake.index,
        target_value=value,
        additional_periods=extension)
    emitter.echo(SUCCESSFUL_STAKE_DIVIDE, color='green', verbosity=1)
    paint_receipt_summary(emitter=emitter,
                          receipt=new_stake.receipt,
                          chain_name=blockchain.client.chain_name)

    # Show the resulting stake list
    paint_stakes(emitter=emitter, stakeholder=STAKEHOLDER)
Example #30
0
def collect_reward(general_config, transacting_staker_options, config_file,
                   staking_reward, policy_fee, withdraw_address, force):
    """Withdraw staking reward."""

    # Setup
    emitter = setup_emitter(general_config)
    STAKEHOLDER = transacting_staker_options.create_character(
        emitter, config_file)
    blockchain = transacting_staker_options.get_blockchain()

    if not staking_reward and not policy_fee:
        raise click.BadArgumentUsage(
            f"Either --staking-reward or --policy-fee must be True to collect rewards."
        )

    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)

    password = None

    if staking_reward:
        # Note: Sending staking / inflation rewards to another account is not allowed.
        reward_amount = NU.from_nunits(STAKEHOLDER.calculate_staking_reward())
        if reward_amount == 0:
            emitter.echo(NO_TOKENS_TO_WITHDRAW, color='red')
            raise click.Abort

        emitter.echo(message=COLLECTING_TOKEN_REWARD.format(
            reward_amount=reward_amount))

        withdrawing_last_portion = STAKEHOLDER.non_withdrawable_stake() == 0
        if not force and withdrawing_last_portion and STAKEHOLDER.mintable_periods(
        ) > 0:
            click.confirm(CONFIRM_COLLECTING_WITHOUT_MINTING, abort=True)

        # Authenticate and Execute
        password = transacting_staker_options.get_password(
            blockchain, client_account)
        STAKEHOLDER.assimilate(password=password)

        staking_receipt = STAKEHOLDER.collect_staking_reward()
        paint_receipt_summary(
            receipt=staking_receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)

    if policy_fee:
        fee_amount = Web3.fromWei(STAKEHOLDER.calculate_policy_fee(), 'ether')
        if fee_amount == 0:
            emitter.echo(NO_FEE_TO_WITHDRAW, color='red')
            raise click.Abort

        emitter.echo(message=COLLECTING_ETH_FEE.format(fee_amount=fee_amount))

        if password is None:
            # Authenticate and Execute
            password = transacting_staker_options.get_password(
                blockchain, client_account)
            STAKEHOLDER.assimilate(password=password)

        policy_receipt = STAKEHOLDER.collect_policy_fee(
            collector_address=withdraw_address)
        paint_receipt_summary(
            receipt=policy_receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)