コード例 #1
0
ファイル: painting.py プロジェクト: y3v63n/nucypher
def paint_preallocation_status(emitter, preallocation_agent,
                               token_agent) -> None:
    blockchain = token_agent.blockchain

    staking_address = preallocation_agent.principal_contract.address

    token_balance = NU.from_nunits(token_agent.get_balance(staking_address))
    eth_balance = Web3.fromWei(blockchain.client.get_balance(staking_address),
                               'ether')
    initial_locked_amount = NU.from_nunits(
        preallocation_agent.initial_locked_amount)
    current_locked_amount = NU.from_nunits(preallocation_agent.unvested_tokens)
    available_amount = NU.from_nunits(preallocation_agent.available_balance)
    end_timestamp = preallocation_agent.end_timestamp

    width = 64
    output = f"""
{" Addresses ".center(width, "-")}
Staking contract: ... {staking_address}
Beneficiary: ........ {preallocation_agent.beneficiary}

{" Locked Tokens ".center(width, "-")}
Initial locked amount: {initial_locked_amount}
Current locked amount: {current_locked_amount}
Locked until: ........ {maya.MayaDT(epoch=end_timestamp)}

{" NU and ETH Balance ".center(width, "-")}
NU balance: .......... {token_balance}
    Available: ....... {available_amount} 
ETH balance: ......... {eth_balance} ETH
"""
    emitter.echo(output)
コード例 #2
0
ファイル: stake.py プロジェクト: gs455/nucypher
def preallocation(click_config,

                  # Stake Options
                  poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
                  beneficiary_address, allocation_filepath,

                  # Preallocation subcommands,
                  action,

                  # Other
                  force):
    """
    Claim token rewards collected by a preallocation contract.
    """

    ### Setup ###
    emitter = _setup_emitter(click_config)

    STAKEHOLDER, blockchain = _create_stakeholder(config_file,
                                                  provider_uri,
                                                  poa,
                                                  light,
                                                  registry_filepath,
                                                  staking_address,
                                                  beneficiary_address=beneficiary_address,
                                                  allocation_filepath=allocation_filepath)
    #############
    # Unauthenticated actions: status

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

    # Authenticated actions: withdraw-tokens

    client_account, staking_address = handle_client_account_for_staking(emitter=emitter,
                                                                        stakeholder=STAKEHOLDER,
                                                                        staking_address=staking_address,
                                                                        individual_allocation=STAKEHOLDER.individual_allocation,
                                                                        force=force)

    password = None
    if not hw_wallet and not blockchain.client.is_local:
        password = get_client_password(checksum_address=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=f'Collecting {unlocked_tokens} from PreallocationEscrow contract {staking_address}...')
        receipt = STAKEHOLDER.withdraw_preallocation_tokens(unlocked_tokens)
        paint_receipt_summary(receipt=receipt,
                              chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
                              emitter=emitter)
コード例 #3
0
def test_nucypher_status_stakers(click_runner, agency_local_registry, stakers):

    # Get all stakers info
    stakers_command = ('stakers', '--registry-filepath',
                       str(agency_local_registry.filepath.absolute()),
                       '--provider', TEST_PROVIDER_URI, '--network',
                       TEMPORARY_DOMAIN)

    result = click_runner.invoke(status,
                                 stakers_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)

    # TODO: Use regex matching instead of this
    assert re.search(f"^Current period: {staking_agent.get_current_period()}",
                     result.output, re.MULTILINE)
    for staker in stakers:
        assert re.search(f"^{staker.checksum_address}", result.output,
                         re.MULTILINE)

    # Get info of only one staker
    some_dude = random.choice(stakers)
    staking_address = some_dude.checksum_address
    stakers_command = ('stakers', '--staking-address', staking_address,
                       '--registry-filepath',
                       str(agency_local_registry.filepath.absolute()),
                       '--provider', TEST_PROVIDER_URI, '--network',
                       TEMPORARY_DOMAIN)

    result = click_runner.invoke(status,
                                 stakers_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    owned_tokens = NU.from_nunits(staking_agent.owned_tokens(staking_address))
    current_locked_tokens = NU.from_nunits(
        staking_agent.get_locked_tokens(staking_address))
    next_locked_tokens = NU.from_nunits(
        staking_agent.get_locked_tokens(staking_address, 1))

    assert re.search(f"^Current period: {staking_agent.get_current_period()}",
                     result.output, re.MULTILINE)
    assert re.search(r"Worker:\s+" + some_dude.worker_address, result.output,
                     re.MULTILINE)
    assert re.search(r"Owned:\s+" + str(round(owned_tokens, 2)), result.output,
                     re.MULTILINE)
    assert re.search(
        r"Staked in current period: " + str(round(current_locked_tokens, 2)),
        result.output, re.MULTILINE)
    assert re.search(
        r"Staked in next period: " + str(round(next_locked_tokens, 2)),
        result.output, re.MULTILINE)
    _minimum, default, _maximum = FEE_RATE_RANGE
    assert f"Min fee rate: {default} wei" in result.output
コード例 #4
0
ファイル: painting.py プロジェクト: zaxayn/nucypher
def paint_stakers(emitter, stakers: List[str], agent) -> None:
    current_period = agent.get_current_period()
    emitter.echo(f"\nCurrent period: {current_period}")
    emitter.echo("\n| Stakers |\n")
    emitter.echo(f"{'Checksum address':42}  Staker information")
    emitter.echo('=' * (42 + 2 + 53))

    for staker in stakers:
        nickname, pairs = nickname_from_seed(staker)
        symbols = f"{pairs[0][1]}  {pairs[1][1]}"
        emitter.echo(f"{staker}  {'Nickname:':10} {nickname} {symbols}")
        tab = " " * len(staker)

        stake = agent.owned_tokens(staker)
        last_confirmed_period = agent.get_last_active_period(staker)
        worker = agent.get_worker_from_staker(staker)
        is_restaking = agent.is_restaking(staker)

        missing_confirmations = current_period - last_confirmed_period
        stake_in_nu = round(NU.from_nunits(stake), 2)
        locked_tokens = round(NU.from_nunits(agent.get_locked_tokens(staker)),
                              2)

        emitter.echo(
            f"{tab}  {'Stake:':10} {stake_in_nu}  (Locked: {locked_tokens})")
        if is_restaking:
            if agent.is_restaking_locked(staker):
                unlock_period = agent.get_restake_unlock_period(staker)
                emitter.echo(
                    f"{tab}  {'Re-staking:':10} Yes  (Locked until period: {unlock_period})"
                )
            else:
                emitter.echo(f"{tab}  {'Re-staking:':10} Yes  (Unlocked)")
        else:
            emitter.echo(f"{tab}  {'Re-staking:':10} No")
        emitter.echo(f"{tab}  {'Activity:':10} ", nl=False)
        if missing_confirmations == -1:
            emitter.echo(f"Next period confirmed (#{last_confirmed_period})",
                         color='green')
        elif missing_confirmations == 0:
            emitter.echo(
                f"Current period confirmed (#{last_confirmed_period}). "
                f"Pending confirmation of next period.",
                color='yellow')
        elif missing_confirmations == current_period:
            emitter.echo(f"Never confirmed activity", color='red')
        else:
            emitter.echo(
                f"Missing {missing_confirmations} confirmations "
                f"(last time for period #{last_confirmed_period})",
                color='red')

        emitter.echo(f"{tab}  {'Worker:':10} ", nl=False)
        if worker == BlockchainInterface.NULL_ADDRESS:
            emitter.echo(f"Worker not set\n", color='red')
        else:
            emitter.echo(f"{worker}\n")
コード例 #5
0
ファイル: painting.py プロジェクト: xbee/nucypher
def paint_stakers(emitter, stakers: List[str], staking_agent, policy_agent) -> None:
    current_period = staking_agent.get_current_period()
    emitter.echo(f"\nCurrent period: {current_period}")
    emitter.echo("\n| Stakers |\n")
    emitter.echo(f"{'Checksum address':42}  Staker information")
    emitter.echo('=' * (42 + 2 + 53))

    for staker in stakers:
        nickname, pairs = nickname_from_seed(staker)
        symbols = f"{pairs[0][1]}  {pairs[1][1]}"
        emitter.echo(f"{staker}  {'Nickname:':10} {nickname} {symbols}")
        tab = " " * len(staker)

        owned_tokens = staking_agent.owned_tokens(staker)
        last_confirmed_period = staking_agent.get_last_active_period(staker)
        worker = staking_agent.get_worker_from_staker(staker)
        is_restaking = staking_agent.is_restaking(staker)
        is_winding_down = staking_agent.is_winding_down(staker)

        missing_confirmations = current_period - last_confirmed_period
        owned_in_nu = round(NU.from_nunits(owned_tokens), 2)
        locked_tokens = round(NU.from_nunits(staking_agent.get_locked_tokens(staker)), 2)

        emitter.echo(f"{tab}  {'Owned:':10} {owned_in_nu}  (Staked: {locked_tokens})")
        if is_restaking:
            if staking_agent.is_restaking_locked(staker):
                unlock_period = staking_agent.get_restake_unlock_period(staker)
                emitter.echo(f"{tab}  {'Re-staking:':10} Yes  (Locked until period: {unlock_period})")
            else:
                emitter.echo(f"{tab}  {'Re-staking:':10} Yes  (Unlocked)")
        else:
            emitter.echo(f"{tab}  {'Re-staking:':10} No")
        emitter.echo(f"{tab}  {'Winding down:':10} {'Yes' if is_winding_down else 'No'}")
        emitter.echo(f"{tab}  {'Activity:':10} ", nl=False)
        if missing_confirmations == -1:
            emitter.echo(f"Next period confirmed (#{last_confirmed_period})", color='green')
        elif missing_confirmations == 0:
            emitter.echo(f"Current period confirmed (#{last_confirmed_period}). "
                         f"Pending confirmation of next period.", color='yellow')
        elif missing_confirmations == current_period:
            emitter.echo(f"Never confirmed activity", color='red')
        else:
            emitter.echo(f"Missing {missing_confirmations} confirmations "
                         f"(last time for period #{last_confirmed_period})", color='red')

        emitter.echo(f"{tab}  {'Worker:':10} ", nl=False)
        if worker == NULL_ADDRESS:
            emitter.echo(f"Worker not set", color='red')
        else:
            emitter.echo(f"{worker}")

        fees = prettify_eth_amount(policy_agent.get_reward_amount(staker))
        emitter.echo(f"{tab}  Unclaimed fees: {fees}")

        min_rate = prettify_eth_amount(policy_agent.get_min_reward_rate(staker))
        emitter.echo(f"{tab}  Min reward rate: {min_rate}")
コード例 #6
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)
コード例 #7
0
def test_stake_status(mock_testerchain, token_economics, mock_staking_agent):

    address = mock_testerchain.etherbase_account
    current_period = 3
    staker_info = StakerInfo(current_committed_period=current_period - 1,
                             next_committed_period=current_period,
                             value=0,
                             last_committed_period=0,
                             lock_restake_until_period=False,
                             completed_work=0,
                             worker_start_period=0,
                             worker=NULL_ADDRESS,
                             flags=bytes())

    mock_staking_agent.get_current_period.return_value = current_period
    mock_staking_agent.get_staker_info.return_value = staker_info

    def make_sub_stake(value, first_locked_period, final_locked_period):
        return Stake(checksum_address=address,
                     first_locked_period=first_locked_period,
                     final_locked_period=final_locked_period,
                     value=value,
                     index=0,
                     staking_agent=mock_staking_agent,
                     economics=token_economics,
                     validate_now=False)

    # Prepare unlocked sub-stake
    nu = NU.from_nunits(2 * token_economics.minimum_allowed_locked - 1)
    stake = make_sub_stake(nu, current_period - 2, current_period - 1)
    assert stake.status() == Stake.Status.UNLOCKED

    # Prepare inactive sub-stake
    # Update staker info and create new state
    stake = make_sub_stake(nu, current_period - 2, current_period - 1)

    staker_info = staker_info._replace(current_committed_period=current_period,
                                       next_committed_period=current_period +
                                       1)
    mock_staking_agent.get_staker_info.return_value = staker_info

    assert stake.status() == Stake.Status.INACTIVE

    # Prepare locked sub-stake
    stake = make_sub_stake(nu, current_period - 2, current_period)
    assert stake.status() == Stake.Status.LOCKED

    # Prepare editable sub-stake
    stake = make_sub_stake(nu, current_period - 2, current_period + 1)
    assert stake.status() == Stake.Status.EDITABLE

    # Prepare divisible sub-stake
    nu = NU.from_nunits(2 * token_economics.minimum_allowed_locked)
    stake = make_sub_stake(nu, current_period - 2, current_period + 1)
    assert stake.status() == Stake.Status.DIVISIBLE
コード例 #8
0
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
コード例 #9
0
    def _learn_about_nodes_contract_info(self):
        agent = self.staking_agent

        block_time = agent.blockchain.client.w3.eth.getBlock('latest').timestamp  # precision in seconds
        current_period = agent.get_current_period()

        nodes_dict = self.known_nodes.abridged_nodes_dict()
        self.log.info(f'Processing {len(nodes_dict)} nodes at '
                      f'{MayaDT(epoch=block_time)} | Period {current_period}')
        data = []
        for staker_address in nodes_dict:
            worker = agent.get_worker_from_staker(staker_address)

            stake = agent.owned_tokens(staker_address)
            staked_nu_tokens = float(NU.from_nunits(stake).to_tokens())
            locked_nu_tokens = float(NU.from_nunits(agent.get_locked_tokens(
                staker_address=staker_address)).to_tokens())

            economics = TokenEconomicsFactory.get_economics(registry=self.registry)
            stakes = StakeList(checksum_address=staker_address, registry=self.registry)
            stakes.refresh()

            # store dates as floats for comparison purposes
            start_date = datetime_at_period(stakes.initial_period,
                                            seconds_per_period=economics.seconds_per_period).datetime().timestamp()
            end_date = datetime_at_period(stakes.terminal_period,
                                          seconds_per_period=economics.seconds_per_period).datetime().timestamp()

            last_confirmed_period = agent.get_last_active_period(staker_address)

            # TODO: do we need to worry about how much information is in memory if number of nodes is
            #  large i.e. should I check for size of data and write within loop if too big
            data.append(self.BLOCKCHAIN_DB_LINE_PROTOCOL.format(
                measurement=self.BLOCKCHAIN_DB_MEASUREMENT,
                staker_address=staker_address,
                worker_address=worker,
                start_date=start_date,
                end_date=end_date,
                stake=staked_nu_tokens,
                locked_stake=locked_nu_tokens,
                current_period=current_period,
                last_confirmed_period=last_confirmed_period,
                timestamp=block_time
            ))

        if not self._blockchain_db_client.write_points(data,
                                                       database=self.BLOCKCHAIN_DB_NAME,
                                                       time_precision='s',
                                                       batch_size=10000,
                                                       protocol='line'):
            # TODO: what do we do here
            self.log.warn(f'Unable to write to database {self.BLOCKCHAIN_DB_NAME} at '
                          f'{MayaDT(epoch=block_time)} | Period {current_period}')
コード例 #10
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':
        painting.paint_preallocation_status(
            emitter=emitter,
            token_agent=STAKEHOLDER.token_agent,
            preallocation_agent=STAKEHOLDER.preallocation_escrow_agent)
        return

    # Authenticated actions: withdraw-tokens

    client_account, staking_address = handle_client_account_for_staking(
        emitter=emitter,
        stakeholder=STAKEHOLDER,
        staking_address=transacting_staker_options.staker_options.
        staking_address,
        individual_allocation=STAKEHOLDER.individual_allocation,
        force=force)

    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=
            f'Collecting {unlocked_tokens} from PreallocationEscrow contract {staking_address}...'
        )
        receipt = STAKEHOLDER.withdraw_preallocation_tokens(unlocked_tokens)
        paint_receipt_summary(
            receipt=receipt,
            chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
            emitter=emitter)
コード例 #11
0
def test_withdraw_from_preallocation(
    click_runner,
    testerchain,
    agency_local_registry,
    stakeholder_configuration_file_location,
    beneficiary,
    preallocation_escrow_agent,
):

    staker_address = preallocation_escrow_agent.principal_contract.address
    token_agent = ContractAgency.get_agent(agent_class=NucypherTokenAgent,
                                           registry=agency_local_registry)
    tokens_in_contract = NU.from_nunits(
        token_agent.get_balance(address=staker_address))
    locked_preallocation = NU.from_nunits(
        preallocation_escrow_agent.unvested_tokens)

    collection_args = (
        'stake',
        'preallocation',
        'status',
        '--config-file',
        stakeholder_configuration_file_location,
        '--allocation-filepath',
        MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
    )

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=True)
    assert result.exit_code == 0
    assert f'NU balance: .......... {tokens_in_contract}' in result.output

    balance_before_collecting = token_agent.get_balance(address=beneficiary)

    collection_args = ('stake', 'preallocation', 'withdraw', '--config-file',
                       stakeholder_configuration_file_location,
                       '--allocation-filepath',
                       MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=True)
    assert result.exit_code == 0
    assert token_agent.get_balance(
        address=staker_address) == locked_preallocation
    withdrawn_amount = tokens_in_contract - locked_preallocation
    balance_after_collecting = token_agent.get_balance(address=beneficiary)
    assert balance_after_collecting == balance_before_collecting + withdrawn_amount
コード例 #12
0
 def staked_tokens(n):
     nu = NU.from_nunits(
         monitor.staking_agent.get_global_locked_tokens())
     return html.Div([
         html.H4('Staked Tokens'),
         html.H5(f"{nu}", id='staked-tokens-value')
     ])
コード例 #13
0
ファイル: actors.py プロジェクト: zaxayn/nucypher
 def current_stake(self) -> NU:
     """
     The total number of staked tokens, either locked or unlocked in the current period.
     """
     stake = self.staking_agent.owned_tokens(staker_address=self.checksum_address)
     nu_stake = NU.from_nunits(stake)
     return nu_stake
コード例 #14
0
def test_stake_increase(click_runner, stakeholder_configuration_file_location,
                        token_economics, testerchain, agency_local_registry,
                        manual_staker):
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)
    stakes = list(staking_agent.get_all_stakes(staker_address=manual_staker))
    stakes_length = len(stakes)
    assert stakes_length > 0

    selection = 0
    new_value = NU.from_nunits(token_economics.minimum_allowed_locked // 10)
    origin_stake = stakes[selection]

    stake_args = ('stake', 'increase', '--config-file',
                  stakeholder_configuration_file_location,
                  '--staking-address', manual_staker, '--value',
                  new_value.to_tokens(), '--index', selection, '--force')

    user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n'
    result = click_runner.invoke(nucypher_cli,
                                 stake_args,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Verify the stake is on-chain
    # Test integration with Agency
    stakes = list(staking_agent.get_all_stakes(staker_address=manual_staker))
    assert len(stakes) == stakes_length

    # Test integration with NU
    _start_period, end_period, value = stakes[selection]
    assert NU(int(value), 'NuNit') == origin_stake.locked_value + new_value
    assert end_period == origin_stake.last_period
コード例 #15
0
def test_participant_status(click_runner, testerchain, agency_local_registry,
                            token_economics):

    tpower = TransactingPower(account=testerchain.client.accounts[2],
                              signer=Web3Signer(testerchain.client))
    bidder = Bidder(transacting_power=tpower,
                    domain=TEMPORARY_DOMAIN,
                    registry=agency_local_registry)

    command = ('status', '--registry-filepath', agency_local_registry.filepath,
               '--participant-address', bidder.checksum_address, '--provider',
               TEST_PROVIDER_URI, '--signer', TEST_PROVIDER_URI, '--network',
               TEMPORARY_DOMAIN)

    result = click_runner.invoke(worklock, command, catch_exceptions=False)
    assert result.exit_code == 0

    # Bidder-specific data is displayed
    assert bidder.checksum_address in result.output
    assert str(bidder.remaining_work) in result.output
    assert str(bidder.available_refund) in result.output

    # Worklock economics are displayed
    assert str(token_economics.worklock_boosting_refund_rate) in result.output
    assert str(NU.from_nunits(
        token_economics.worklock_supply)) in result.output
コード例 #16
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)
コード例 #17
0
 def staked_tokens(n, latest_crawler_stats):
     data = self.verify_cached_stats(latest_crawler_stats)
     staked = NU.from_nunits(data['global_locked_tokens'])
     return html.Div([
         html.H4('Staked Tokens'),
         html.H5(f"{staked}", id='staked-tokens-value')
     ])
コード例 #18
0
def test_nucypher_status_locked_tokens(click_runner, testerchain,
                                       agency_local_registry, stakers):

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)
    # All workers make a commitment
    for ursula in testerchain.ursulas_accounts:
        staking_agent.commit_to_next_period(worker_address=ursula)
    testerchain.time_travel(periods=1)

    periods = 2
    status_command = ('locked-tokens', '--registry-filepath',
                      agency_local_registry.filepath, '--provider',
                      TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN,
                      '--periods', periods)
    light_parameter = [False, True]
    for light in light_parameter:
        testerchain.is_light = light
        result = click_runner.invoke(status,
                                     status_command,
                                     catch_exceptions=False)
        assert result.exit_code == 0

        current_period = staking_agent.get_current_period()
        all_locked = NU.from_nunits(
            staking_agent.get_global_locked_tokens(at_period=current_period))
        assert re.search(f"Locked Tokens for next {periods} periods",
                         result.output, re.MULTILINE)
        assert re.search(f"Min: {all_locked} - Max: {all_locked}",
                         result.output, re.MULTILINE)
コード例 #19
0
ファイル: test_staker.py プロジェクト: datanetworks/nucypher
def test_staker_increases_stake(staker, token_economics):
    stake_index = 0
    origin_stake = staker.stakes[stake_index]
    additional_amount = NU.from_nunits(token_economics.minimum_allowed_locked // 100)

    with pytest.raises(ValueError):
        staker.increase_stake(stake=origin_stake)
    # Can't use amount and entire balance flag together
    with pytest.raises(ValueError):
        staker.increase_stake(stake=origin_stake, amount=additional_amount, entire_balance=True)

    staker.increase_stake(stake=origin_stake, amount=additional_amount)

    stake = staker.stakes[stake_index]
    assert stake.first_locked_period == origin_stake.first_locked_period
    assert stake.final_locked_period == origin_stake.final_locked_period
    assert stake.value == origin_stake.value + additional_amount

    # Provided stake must be part of current stakes
    with pytest.raises(ValueError):
        staker.increase_stake(stake=origin_stake, amount=additional_amount)
    stake.index = len(staker.stakes)
    with pytest.raises(ValueError):
        staker.increase_stake(stake=stake, amount=additional_amount)
    stake.index = stake_index

    # Try to increase again using entire balance
    origin_stake = stake
    balance = staker.token_balance
    staker.increase_stake(stake=stake, entire_balance=True)

    stake = staker.stakes[stake_index]
    assert stake.first_locked_period == origin_stake.first_locked_period
    assert stake.final_locked_period == origin_stake.final_locked_period
    assert stake.value == origin_stake.value + balance
コード例 #20
0
ファイル: painting.py プロジェクト: y3v63n/nucypher
def paint_bidder_status(emitter, bidder):
    claim = NU.from_nunits(bidder.available_claim)
    if claim > bidder.economics.maximum_allowed_locked:
        claim = f"{claim} (Above the allowed max. The bid will be partially refunded)"

    message = f"""
WorkLock Participant {bidder.checksum_address}
=====================================================
Total Bid ............ {prettify_eth_amount(bidder.get_deposited_eth)}
Tokens Allocated ..... {claim}
Tokens Claimed? ...... {"Yes" if bidder._has_claimed else "No"}"""

    compensation = bidder.available_compensation
    if compensation:
        message += f"""
Unspent Bid Amount ... {prettify_eth_amount(compensation)}"""

    message += f"""\n
Completed Work ....... {bidder.completed_work}
Available Refund ..... {prettify_eth_amount(bidder.available_refund)}

Refunded Work ........ {bidder.refunded_work}
Remaining Work ....... {bidder.remaining_work}
"""

    emitter.echo(message)
    return
コード例 #21
0
ファイル: actors.py プロジェクト: existentializm/nucypher
 def locked_tokens(self, periods: int = 0) -> NU:
     """Returns the amount of tokens this staker has locked for a given duration in periods."""
     self.stakes.refresh()
     raw_value = self.staking_agent.get_locked_tokens(
         staker_address=self.checksum_address, periods=periods)
     value = NU.from_nunits(raw_value)
     return value
コード例 #22
0
def test_nucypher_status_stakers(click_runner, testerchain, test_registry,
                                 agency, stakers):

    # Get all stakers info
    stakers_command = ('stakers', '--registry-filepath',
                       MOCK_REGISTRY_FILEPATH, '--provider', TEST_PROVIDER_URI,
                       '--poa')

    result = click_runner.invoke(status,
                                 stakers_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=test_registry)

    # TODO: Use regex matching instead of this
    assert re.search(f"^Current period: {staking_agent.get_current_period()}",
                     result.output, re.MULTILINE)
    for staker in stakers:
        assert re.search(f"^{staker.checksum_address}", result.output,
                         re.MULTILINE)

    # Get info of only one staker
    some_dude = random.choice(stakers)
    staking_address = some_dude.checksum_address
    stakers_command = ('stakers', '--staking-address', staking_address,
                       '--registry-filepath', MOCK_REGISTRY_FILEPATH,
                       '--provider', TEST_PROVIDER_URI, '--poa')

    result = click_runner.invoke(status,
                                 stakers_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    owned_tokens = NU.from_nunits(staking_agent.owned_tokens(staking_address))
    locked_tokens = NU.from_nunits(
        staking_agent.get_locked_tokens(staking_address))

    assert re.search(f"^Current period: {staking_agent.get_current_period()}",
                     result.output, re.MULTILINE)
    assert re.search(r"Worker:\s+" + some_dude.worker_address, result.output,
                     re.MULTILINE)
    assert re.search(r"Owned:\s+" + str(round(owned_tokens, 2)), result.output,
                     re.MULTILINE)
    assert re.search(r"Staked: " + str(round(locked_tokens, 2)), result.output,
                     re.MULTILINE)
コード例 #23
0
ファイル: crawler.py プロジェクト: tuxxy/nucypher-monitor
 def _measure_top_stakers(self) -> dict:
     _, stakers = self.staking_agent.get_all_active_stakers(periods=1)
     data = dict()
     for staker, stake in stakers:
         staker_address = to_checksum_address(staker)
         data[staker_address] = float(NU.from_nunits(stake).to_tokens())
     data = dict(sorted(data.items(), key=lambda s: s[1], reverse=True))
     return data
コード例 #24
0
def test_divide_interactive(click_runner, mocker, surrogate_staker,
                            surrogate_stakes, mock_staking_agent,
                            token_economics, mock_testerchain):
    mock_refresh_stakes = mocker.spy(Staker, 'refresh_stakes')

    selected_index = 0
    sub_stake_index = len(surrogate_stakes) - 1
    lock_periods = 10
    min_allowed_locked = token_economics.minimum_allowed_locked
    target_value = min_allowed_locked

    mock_staking_agent.get_worker_from_staker.return_value = surrogate_staker.checksum_address

    command = ('divide', '--provider', MOCK_PROVIDER_URI, '--network',
               TEMPORARY_DOMAIN)

    user_input = '\n'.join(
        (str(selected_index), str(sub_stake_index),
         str(NU.from_nunits(target_value).to_tokens()), str(lock_periods), YES,
         INSECURE_DEVELOPMENT_PASSWORD))
    result = click_runner.invoke(stake,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    assert PROMPT_STAKE_DIVIDE_VALUE.format(
        minimum=NU.from_nunits(min_allowed_locked),
        maximum=NU.from_nunits(min_allowed_locked + 1)) in result.output
    assert PROMPT_STAKE_EXTEND_VALUE in result.output
    assert CONFIRM_BROADCAST_STAKE_DIVIDE in result.output
    assert SUCCESSFUL_STAKE_DIVIDE in result.output

    mock_staking_agent.get_all_stakes.assert_called()
    mock_staking_agent.get_current_period.assert_called()
    mock_refresh_stakes.assert_called()
    mock_staking_agent.divide_stake.assert_called_once_with(
        staker_address=surrogate_staker.checksum_address,
        stake_index=sub_stake_index,
        target_value=target_value,
        periods=lock_periods)
    mock_staking_agent.assert_only_transactions(
        [mock_staking_agent.divide_stake])
    mock_staking_agent.get_substake_info.assert_called_once_with(
        staker_address=surrogate_staker.checksum_address,
        stake_index=sub_stake_index)
コード例 #25
0
ファイル: crawler.py プロジェクト: tuxxy/nucypher-monitor
 def _measure_future_locked_tokens(self, periods: int = 365):
     period_range = range(1, periods + 1)
     token_counter = dict()
     for day in period_range:
         tokens, stakers = self.staking_agent.get_all_active_stakers(
             periods=day)
         token_counter[day] = (float(NU.from_nunits(tokens).to_tokens()),
                               len(stakers))
     return dict(token_counter)
コード例 #26
0
 def _snapshot_future_locked_tokens():
     # TODO: Consider adopting this method here, or moving it to the crawler with database storage
     period_range = range(1, 365 + 1)
     token_counter = dict()
     for day in period_range:
         tokens, stakers = staking_agent.get_all_active_stakers(periods=day)
         token_counter[day] = (NU.from_nunits(tokens).to_tokens(),
                               len(stakers))
     return token_counter
コード例 #27
0
ファイル: confirm.py プロジェクト: chaoticx-org/nucypher
def confirm_large_and_or_long_stake(value: NU = None, lock_periods: int = None, economics: BaseEconomics = None) -> bool:
    """Interactively confirm a large stake and/or a long stake duration."""
    if economics and value and (value > (NU.from_nunits(economics.minimum_allowed_locked) * 10)):  # > 10x min stake
        click.confirm(CONFIRM_LARGE_STAKE_VALUE.format(value=value), abort=True)
    if economics and lock_periods and (lock_periods > economics.maximum_rewarded_periods):  # > 1 year
        lock_days = (lock_periods * economics.hours_per_period) // 24
        click.confirm(CONFIRM_LARGE_STAKE_DURATION.format(lock_periods=lock_periods, lock_days=lock_days),
                      abort=True)
    return True
コード例 #28
0
ファイル: stake.py プロジェクト: gs455/nucypher
def collect_reward(click_config,

                   # Stake Options
                   poa, light, registry_filepath, config_file, provider_uri, staking_address, hw_wallet,
                   beneficiary_address, allocation_filepath,

                   # Other
                   staking_reward, policy_reward, withdraw_address, force):
    """
    Withdraw staking reward.
    """

    ### Setup ###
    emitter = _setup_emitter(click_config)

    STAKEHOLDER, blockchain = _create_stakeholder(config_file,
                                                  provider_uri,
                                                  poa,
                                                  light,
                                                  registry_filepath,
                                                  staking_address,
                                                  beneficiary_address=beneficiary_address,
                                                  allocation_filepath=allocation_filepath)
    #############

    client_account, staking_address = handle_client_account_for_staking(emitter=emitter,
                                                                        stakeholder=STAKEHOLDER,
                                                                        staking_address=staking_address,
                                                                        individual_allocation=STAKEHOLDER.individual_allocation,
                                                                        force=force)

    password = None
    if not hw_wallet and not blockchain.client.is_local:
        password = get_client_password(checksum_address=client_account)

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

    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=f'Collecting {reward_amount} from staking rewards...')
        staking_receipt = STAKEHOLDER.collect_staking_reward()
        paint_receipt_summary(receipt=staking_receipt,
                              chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
                              emitter=emitter)

    if policy_reward:
        reward_amount = Web3.fromWei(STAKEHOLDER.calculate_policy_reward(), 'ether')
        emitter.echo(message=f'Collecting {reward_amount} ETH from policy rewards...')
        policy_receipt = STAKEHOLDER.collect_policy_reward(collector_address=withdraw_address)
        paint_receipt_summary(receipt=policy_receipt,
                              chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
                              emitter=emitter)
コード例 #29
0
ファイル: test_worklock_cli.py プロジェクト: y3v63n/nucypher
def test_status(click_runner, testerchain, agency_local_registry, token_economics):
    command = ('status',
               '--registry-filepath', agency_local_registry.filepath,
               '--provider', TEST_PROVIDER_URI,
               '--network', TEMPORARY_DOMAIN)

    result = click_runner.invoke(worklock, command, catch_exceptions=False)

    assert result.exit_code == 0
    assert str(NU.from_nunits(token_economics.worklock_supply)) in result.output
    assert str(Web3.fromWei(token_economics.worklock_min_allowed_bid, 'ether')) in result.output
コード例 #30
0
def test_beneficiary_withdraws_tokens(testerchain, agent, agency,
                                      allocation_value,
                                      mock_transacting_power_activation,
                                      token_economics):
    token_agent, staking_agent, policy_agent = agency
    deployer_address, beneficiary_address, *everybody_else = testerchain.client.accounts

    contract_address = agent.contract_address
    assert token_agent.get_balance(
        address=contract_address
    ) == agent.unvested_tokens == agent.initial_locked_amount

    # Trying to withdraw the tokens now fails, obviously
    initial_amount = token_agent.get_balance(address=contract_address)
    with pytest.raises((TransactionFailed, ValueError)):
        agent.withdraw_tokens(value=initial_amount)

    # Let's deposit some of them (30% of initial amount)
    staked_amount = 3 * initial_amount // 10
    mock_transacting_power_activation(account=agent.beneficiary,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)
    _receipt = agent.deposit_as_staker(
        amount=staked_amount,
        lock_periods=token_economics.minimum_locked_periods)

    # Trying to withdraw the remaining fails too:
    # The locked amount is equal to the initial deposit (100% of the tokens).
    # Since 30% are staked, the locked amount is reduced by that 30% when withdrawing,
    # which results in an effective lock of 70%. However, the contract also has 70%, which means that, effectively,
    # the beneficiary can only withdraw 0 tokens.
    assert agent.available_balance == 0
    with pytest.raises((TransactionFailed, ValueError)):
        agent.withdraw_tokens(value=initial_amount - staked_amount)
    agent.withdraw_tokens(value=0)

    # Now let's assume the contract has more tokens (e.g., coming from staking rewards).
    # The beneficiary should be able to collect this excess.
    mocked_rewards = NU.from_nunits(1000)
    token_airdrop(token_agent=token_agent,
                  amount=mocked_rewards,
                  origin=deployer_address,
                  addresses=[contract_address])
    assert agent.available_balance == mocked_rewards
    agent.withdraw_tokens(value=int(mocked_rewards))

    # Once the lock passes, the beneficiary can withdraw what's left
    testerchain.time_travel(seconds=TEST_LOCK_DURATION_IN_SECONDS)
    receipt = agent.withdraw_tokens(value=initial_amount - staked_amount)
    assert receipt['status'] == 1, "Transaction Rejected"
    assert token_agent.get_balance(address=contract_address) == 0
    assert token_agent.get_balance(
        address=beneficiary_address
    ) == initial_amount - staked_amount + mocked_rewards