Ejemplo n.º 1
0
def test_get_remaining_work(testerchain, agency, token_economics,
                            test_registry):
    agent = ContractAgency.get_agent(WorkLockAgent, registry=test_registry)
    bidder = testerchain.unassigned_accounts[0]
    remaining = agent.get_remaining_work(checksum_address=bidder)
    assert remaining == 35905203136136849607983
Ejemplo n.º 2
0
def test_deploy_idle_network(testerchain, deployment_progress, test_registry):
    origin, *everybody_else = testerchain.client.accounts

    #
    # Nucypher Token
    #
    token_deployer = NucypherTokenDeployer(registry=test_registry, deployer_address=origin)
    assert token_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert token_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not token_deployer.is_deployed()

    token_deployer.deploy(progress=deployment_progress)
    assert token_deployer.is_deployed()

    token_agent = NucypherTokenAgent(registry=test_registry)
    assert token_agent.contract_address == token_deployer.contract_address

    another_token_agent = token_deployer.make_agent()
    assert another_token_agent.contract_address == token_deployer.contract_address == token_agent.contract_address

    #
    # StakingEscrow - in IDLE mode, i.e. without activation steps (approve_funding and initialize)
    #
    stakers_escrow_secret = os.urandom(DispatcherDeployer._secret_length)
    staking_escrow_deployer = StakingEscrowDeployer(registry=test_registry, deployer_address=origin)
    assert staking_escrow_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert staking_escrow_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not staking_escrow_deployer.is_deployed()

    staking_escrow_deployer.deploy(secret_hash=keccak(stakers_escrow_secret),
                                   progress=deployment_progress,
                                   deployment_mode=constants.IDLE)
    assert staking_escrow_deployer.is_deployed()

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
    assert staking_agent.contract_address == staking_escrow_deployer.contract_address

    # The contract has no tokens yet
    assert token_agent.get_balance(staking_agent.contract_address) == 0

    #
    # Policy Manager
    #
    policy_manager_secret = os.urandom(DispatcherDeployer._secret_length)
    policy_manager_deployer = PolicyManagerDeployer(registry=test_registry, deployer_address=origin)

    assert policy_manager_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert policy_manager_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not policy_manager_deployer.is_deployed()

    policy_manager_deployer.deploy(secret_hash=keccak(policy_manager_secret), progress=deployment_progress)
    assert policy_manager_deployer.is_deployed()

    policy_agent = policy_manager_deployer.make_agent()
    assert policy_agent.contract_address == policy_manager_deployer.contract_address

    #
    # Adjudicator
    #
    adjudicator_secret = os.urandom(DispatcherDeployer._secret_length)
    adjudicator_deployer = AdjudicatorDeployer(registry=test_registry, deployer_address=origin)

    assert adjudicator_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert adjudicator_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not adjudicator_deployer.is_deployed()

    adjudicator_deployer.deploy(secret_hash=keccak(adjudicator_secret), progress=deployment_progress)
    assert adjudicator_deployer.is_deployed()

    adjudicator_agent = adjudicator_deployer.make_agent()
    assert adjudicator_agent.contract_address == adjudicator_deployer.contract_address
Ejemplo n.º 3
0
def test_bond_worker(software_stakeholder, manual_worker, test_registry):
    software_stakeholder.bond_worker(worker_address=manual_worker)
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=test_registry)
    assert staking_agent.get_worker_from_staker(
        staker_address=software_stakeholder.checksum_address) == manual_worker
Ejemplo n.º 4
0
    def __init__(self,
                 influx_host: str,
                 influx_port: int,
                 crawler_http_port: int = DEFAULT_CRAWLER_HTTP_PORT,
                 registry: BaseContractRegistry = None,
                 node_storage_filepath: str = CrawlerNodeStorage.
                 DEFAULT_DB_FILEPATH,
                 refresh_rate=DEFAULT_REFRESH_RATE,
                 restart_on_error=True,
                 *args,
                 **kwargs):

        # Settings
        self.federated_only = False  # Nope - for compatibility with Learner TODO # nucypher/466
        Teacher.set_federated_mode(False)

        self.registry = registry or InMemoryContractRegistry.from_latest_publication(
        )
        self._refresh_rate = refresh_rate
        self._restart_on_error = restart_on_error

        # TODO: Needs cleanup
        # Tracking
        node_storage = CrawlerNodeStorage(
            storage_filepath=node_storage_filepath)

        class MonitoringTracker(FleetStateTracker):
            def record_fleet_state(self, *args, **kwargs):
                new_state_or_none = super().record_fleet_state(*args, **kwargs)
                if new_state_or_none:
                    _, new_state = new_state_or_none
                    state = self.abridged_state_details(new_state)
                    node_storage.store_state_metadata(state)

        self.tracker_class = MonitoringTracker

        super().__init__(save_metadata=True,
                         node_storage=node_storage,
                         *args,
                         **kwargs)
        self.log = Logger(self.__class__.__name__)
        self.log.info(
            f"Storing node metadata in DB: {node_storage.db_filepath}")
        self.log.info(
            f"Storing blockchain metadata in DB: {influx_host}:{influx_port}")

        # In-memory Metrics
        self._stats = {'status': 'initializing'}
        self._crawler_client = None

        # Initialize InfluxDB
        self._db_host = influx_host
        self._db_port = influx_port
        self._influx_client = None

        # Agency
        self.staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                                      registry=self.registry)

        # Crawler Tasks
        self.__collection_round = 0
        self.__collecting_nodes = False  # thread tracking
        self.__collecting_stats = False
        self.__events_from_block = 0  # from the beginning
        self.__collecting_events = False

        self._node_details_task = task.LoopingCall(self._learn_about_nodes)
        self._stats_collection_task = task.LoopingCall(self._collect_stats,
                                                       threaded=True)
        self._events_collection_task = task.LoopingCall(self._collect_events)

        # JSON Endpoint
        self._crawler_http_port = crawler_http_port
        self._flask = None
Ejemplo n.º 5
0
def paint_worklock_status(emitter, registry: BaseContractRegistry):
    from maya import MayaDT

    worklock_agent = ContractAgency.get_agent(WorkLockAgent, registry=registry)  # type: WorkLockAgent
    blockchain = worklock_agent.blockchain

    # Time
    bidding_start = MayaDT(worklock_agent.contract.functions.startBidDate().call())
    bidding_end = MayaDT(worklock_agent.contract.functions.endBidDate().call())
    cancellation_end = MayaDT(worklock_agent.contract.functions.endCancellationDate().call())

    bidding_duration = bidding_end - bidding_start
    cancellation_duration = cancellation_end - bidding_start

    now = maya.now()
    bidding_remaining = bidding_end - now if bidding_end > now else 'Closed'
    cancellation_remaining = cancellation_end - now if cancellation_end > now else "Closed"

    cancellation_open = bidding_start <= now <= cancellation_end
    bidding_open = bidding_start <= now <= bidding_end

    # Refund
    refund_multiple = worklock_agent.contract.functions.boostingRefund().call() \
                      / worklock_agent.contract.functions.SLOWING_REFUND().call()

    payload = f"""
Time
══════════════════════════════════════════════════════

Contribution Period ({'Open' if bidding_open else 'Closed'})
------------------------------------------------------
Claims Available ...... {'Yes' if worklock_agent.is_claiming_available() else 'No'}
Start Date ............ {bidding_start}
End Date .............. {bidding_end}
Duration .............. {bidding_duration}
Time Remaining ........ {bidding_remaining} 

Cancellation Period ({'Open' if cancellation_open else 'Closed'})
------------------------------------------------------
End Date .............. {cancellation_end}
Duration .............. {cancellation_duration}
Time Remaining ........ {cancellation_remaining}
 
 
Economics
══════════════════════════════════════════════════════

Participation
------------------------------------------------------
Lot Size .............. {NU.from_nunits(worklock_agent.lot_value)} 
Min. Allowed Bid ...... {prettify_eth_amount(worklock_agent.minimum_allowed_bid)}
Participants .......... {worklock_agent.get_bidders_population()}
ETH Supply ............ {prettify_eth_amount(worklock_agent.get_eth_supply())}
ETH Pool .............. {prettify_eth_amount(blockchain.client.get_balance(worklock_agent.contract_address))}

Base (minimum bid)
------------------------------------------------------
Base Deposit Rate ..... {worklock_agent.get_base_deposit_rate()} NU per base ETH

Bonus (surplus over minimum bid)
------------------------------------------------------
Bonus ETH Supply ...... {prettify_eth_amount(worklock_agent.get_bonus_eth_supply())}
Bonus Lot Size ........ {NU.from_nunits(worklock_agent.get_bonus_lot_value())}
Bonus Deposit Rate .... {worklock_agent.get_bonus_deposit_rate()} NU per bonus ETH

Refunds
------------------------------------------------------
Refund Rate Multiple .. {refund_multiple:.2f}
Bonus Refund Rate ..... {worklock_agent.get_bonus_refund_rate()} units of work to unlock 1 bonus ETH
Base Refund Rate ...... {worklock_agent.get_base_refund_rate()} units of work to unlock 1 base ETH

    * NOTE: bonus ETH is refunded before base ETH
    """
    emitter.echo(payload)
    return
Ejemplo n.º 6
0
def test_get_remaining_work(testerchain, agency, token_economics, test_registry):
    agent = ContractAgency.get_agent(WorkLockAgent, registry=test_registry)
    bidder = testerchain.client.accounts[0]
    remaining = agent.get_remaining_work(checksum_address=bidder)
    assert remaining > 0
Ejemplo n.º 7
0
def test_unknown_contract(testerchain, test_registry):
    with pytest.raises(BaseContractRegistry.UnknownContract) as exception:
        _staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                                  registry=test_registry)

    assert exception.value.args[0] == StakingEscrowAgent.registry_contract_name
Ejemplo n.º 8
0
def test_get_min_authorization(agency, test_registry, application_economics):
    application_agent = ContractAgency.get_agent(PREApplicationAgent,
                                                 registry=test_registry)
    result = application_agent.get_min_authorization()
    assert result == application_economics.min_authorization
Ejemplo n.º 9
0
def test_get_min_seconds(agency, test_registry, application_economics):
    application_agent = ContractAgency.get_agent(PREApplicationAgent,
                                                 registry=test_registry)
    result = application_agent.get_min_operator_seconds()
    assert result == application_economics.min_operator_seconds
Ejemplo n.º 10
0
def test_stake_via_contract(click_runner, custom_filepath,
                            agency_local_registry, mock_allocation_registry,
                            testerchain,
                            stakeholder_configuration_file_location,
                            stake_value, token_economics, agency, beneficiary,
                            preallocation_escrow_agent):

    #
    # Inital setup and checks: beneficiary and pre-allocation contract
    #

    # First, let's be sure the beneficiary is in the allocation registry...
    assert mock_allocation_registry.is_beneficiary_enrolled(beneficiary)

    # ... and that the pre-allocation contract has enough tokens
    preallocation_contract_address = preallocation_escrow_agent.principal_contract.address
    token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                           registry=agency_local_registry)
    assert token_agent.get_balance(preallocation_contract_address
                                   ) >= token_economics.minimum_allowed_locked

    # Let's not forget to create a stakeholder
    init_args = ('stake', 'init-stakeholder', '--poa', '--config-root',
                 custom_filepath, '--provider', TEST_PROVIDER_URI, '--network',
                 TEMPORARY_DOMAIN, '--registry-filepath',
                 agency_local_registry.filepath)

    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    with open(stakeholder_configuration_file_location) as f:
        print(f.read())

    #
    # The good stuff: Using `nucypher stake create --escrow`
    #

    # Staking contract has no stakes yet
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)
    stakes = list(
        staking_agent.get_all_stakes(
            staker_address=preallocation_contract_address))
    assert not stakes

    stake_args = ('stake', 'create', '--config-file',
                  stakeholder_configuration_file_location,
                  '--allocation-filepath', MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
                  '--value', str(stake_value.to_tokens()), '--lock-periods',
                  token_economics.minimum_locked_periods, '--force')

    # TODO: This test is writing to the default system directory and ignoring updates to the passed filepath
    user_input = '0\n' + 'Y\n' + f'{INSECURE_DEVELOPMENT_PASSWORD}\n' + 'Y\n'
    result = click_runner.invoke(nucypher_cli,
                                 stake_args,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Test integration with BaseConfiguration
    with open(stakeholder_configuration_file_location, 'r') as config_file:
        _config_data = json.loads(config_file.read())

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

    # Test integration with NU
    start_period, end_period, value = stakes[0]
    assert NU(int(value), 'NuNit') == stake_value
    assert (end_period -
            start_period) == token_economics.minimum_locked_periods - 1

    # Test integration with Stake
    stake = Stake.from_stake_info(
        index=0,
        checksum_address=preallocation_contract_address,
        stake_info=stakes[0],
        staking_agent=staking_agent,
        economics=token_economics)
    assert stake.value == stake_value
    assert stake.duration == token_economics.minimum_locked_periods
Ejemplo n.º 11
0
def paint_deployer_contract_inspection(emitter, administrator) -> None:

    blockchain = BlockchainInterfaceFactory.get_interface()
    token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                           registry=administrator.registry)

    sep = '-' * 45
    emitter.echo(sep)

    contract_payload = f"""

* Web3 Provider
====================================================================

Provider URI ............. {blockchain.provider_uri}
Registry  ................ {administrator.registry.filepath}

* Standard Deployments
=====================================================================

NucypherToken ........... {token_agent.contract_address}
    ~ Ethers ............ {Web3.fromWei(blockchain.client.get_balance(token_agent.contract_address), 'ether')} ETH
    ~ Tokens ............ {NU.from_nunits(token_agent.get_balance(token_agent.contract_address))}"""
    emitter.echo(contract_payload)

    banner = """
* Proxy-Contract Deployments
====================================================================="""
    emitter.echo(banner)

    for contract_deployer_class in administrator.dispatched_upgradeable_deployer_classes:
        try:
            bare_contract = blockchain.get_contract_by_name(
                name=contract_deployer_class.contract_name,
                proxy_name=DispatcherDeployer.contract_name,
                registry=administrator.registry,
                use_proxy_address=False)

            dispatcher_deployer = DispatcherDeployer(
                registry=administrator.registry,
                target_contract=bare_contract,
                deployer_address=administrator.deployer_address,
                bare=True)  # acquire agency for the dispatcher itself.

            agent = contract_deployer_class.agency(
                registry=administrator.registry, contract=bare_contract)

            proxy_payload = f"""
{agent.contract_name} .... {bare_contract.address}
    ~ Owner .............. {bare_contract.functions.owner().call()}
    ~ Ethers ............. {Web3.fromWei(blockchain.client.get_balance(dispatcher_deployer.contract_address), 'ether')} ETH
    ~ Tokens ............. {NU.from_nunits(token_agent.get_balance(dispatcher_deployer.contract_address))}
    ~ Dispatcher ......... {dispatcher_deployer.contract_address}
        ~ Owner .......... {dispatcher_deployer.contract.functions.owner().call()}
        ~ Target ......... {dispatcher_deployer.contract.functions.target().call()}
        ~ Ethers ......... {Web3.fromWei(blockchain.client.get_balance(dispatcher_deployer.contract_address), 'ether')} ETH
        ~ Tokens ......... {NU.from_nunits(token_agent.get_balance(dispatcher_deployer.contract_address))}"""
            emitter.echo(proxy_payload)
            emitter.echo(sep, nl=False)

        except BaseContractRegistry.UnknownContract:
            message = f"\n{contract_deployer_class.contract_name} is not enrolled in {administrator.registry.filepath}"
            emitter.echo(message, color='yellow')
            emitter.echo(sep, nl=False)

    try:

        #
        # UserEscrowProxy
        #

        user_escrow_proxy_agent = UserEscrowAgent.UserEscrowProxyAgent(
            registry=administrator.registry)
        bare_contract = blockchain.get_contract_by_name(
            name=user_escrow_proxy_agent.contract_name,
            proxy_name=LibraryLinkerDeployer.contract_name,
            use_proxy_address=False,
            registry=administrator.registry)

        linker_deployer = LibraryLinkerDeployer(
            registry=administrator.registry,
            target_contract=bare_contract,
            deployer_address=administrator.deployer_address,
            bare=True)  # acquire agency for the dispatcher itself.

        user_escrow_payload = f"""
UserEscrowProxy .......... {bare_contract.address}
    ~ LibraryLinker ...... {linker_deployer.contract.address}
        ~ Owner .......... {linker_deployer.contract.functions.owner().call()}
        ~ Target ......... {linker_deployer.contract.functions.target().call()}"""
        emitter.echo(user_escrow_payload)
        emitter.echo(sep)

    except BaseContractRegistry.UnknownContract:
        message = f"\nUserEscrowProxy is not enrolled in {administrator.registry.filepath}"
        emitter.echo(message, color='yellow')

    return
Ejemplo n.º 12
0
def test_collect_rewards_integration(
        click_runner, testerchain, agency_local_registry,
        stakeholder_configuration_file_location, blockchain_alice,
        blockchain_bob, random_policy_label, beneficiary,
        preallocation_escrow_agent, mock_allocation_registry, manual_worker,
        token_economics, mock_transacting_power_activation, stake_value,
        policy_value, policy_rate):
    # Disable re-staking
    restake_args = ('stake', 'restake', '--disable', '--config-file',
                    stakeholder_configuration_file_location,
                    '--allocation-filepath',
                    MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 restake_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    half_stake_time = token_economics.minimum_locked_periods // 2  # Test setup
    logger = Logger("Test-CLI")  # Enter the Teacher's Logger, and
    current_period = 0  # State the initial period for incrementing

    staker_address = preallocation_escrow_agent.principal_contract.address
    worker_address = manual_worker

    # The staker is staking.
    stakes = StakeList(registry=agency_local_registry,
                       checksum_address=staker_address)
    stakes.refresh()
    assert stakes

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)
    assert worker_address == staking_agent.get_worker_from_staker(
        staker_address=staker_address)

    ursula_port = select_test_port()
    ursula = Ursula(is_me=True,
                    checksum_address=staker_address,
                    worker_address=worker_address,
                    registry=agency_local_registry,
                    rest_host='127.0.0.1',
                    rest_port=ursula_port,
                    start_working_now=False,
                    network_middleware=MockRestMiddleware())

    MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula
    assert ursula.worker_address == worker_address
    assert ursula.checksum_address == staker_address

    mock_transacting_power_activation(account=worker_address,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # Confirm for half the first stake duration
    for _ in range(half_stake_time):
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.confirm_activity()
        testerchain.time_travel(periods=1)
        current_period += 1

    # Alice creates a policy and grants Bob access
    blockchain_alice.selection_buffer = 1

    M, N = 1, 1
    days = 3
    now = testerchain.w3.eth.getBlock(block_identifier='latest').timestamp
    expiration = maya.MayaDT(now).add(days=days - 1)
    blockchain_policy = blockchain_alice.grant(bob=blockchain_bob,
                                               label=random_policy_label,
                                               m=M,
                                               n=N,
                                               value=policy_value,
                                               expiration=expiration,
                                               handpicked_ursulas={ursula})

    # Ensure that the handpicked Ursula was selected for the policy
    arrangement = list(blockchain_policy._accepted_arrangements)[0]
    assert arrangement.ursula == ursula

    # Bob learns about the new staker and joins the policy
    blockchain_bob.start_learning_loop()
    blockchain_bob.remember_node(node=ursula)
    blockchain_bob.join_policy(random_policy_label,
                               bytes(blockchain_alice.stamp))

    # Enrico Encrypts (of course)
    enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key,
                    network_middleware=MockRestMiddleware())

    verifying_key = blockchain_alice.stamp.as_umbral_pubkey()

    for index in range(half_stake_time - 5):
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.confirm_activity()

        # Encrypt
        random_data = os.urandom(random.randrange(20, 100))
        message_kit, signature = enrico.encrypt_message(message=random_data)

        # Decrypt
        cleartexts = blockchain_bob.retrieve(message_kit,
                                             enrico=enrico,
                                             alice_verifying_key=verifying_key,
                                             label=random_policy_label)
        assert random_data == cleartexts[0]

        # Ursula Staying online and the clock advancing
        testerchain.time_travel(periods=1)
        current_period += 1

    # Finish the passage of time
    for _ in range(
            5 - 1
    ):  # minus 1 because the first period was already confirmed in test_ursula_run
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.confirm_activity()
        current_period += 1
        testerchain.time_travel(periods=1)

    #
    # WHERES THE MONEY URSULA?? - Collecting Rewards
    #

    # The address the client wants Ursula to send policy rewards to
    burner_wallet = testerchain.w3.eth.account.create(
        INSECURE_DEVELOPMENT_PASSWORD)

    # The policy rewards wallet is initially empty, because it is freshly created
    assert testerchain.client.get_balance(burner_wallet.address) == 0

    # Rewards will be unlocked after the
    # final confirmed period has passed (+1).
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
    testerchain.time_travel(periods=1)
    current_period += 1
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")

    # Since we are mocking the blockchain connection, manually consume the transacting power of the Beneficiary.
    mock_transacting_power_activation(account=beneficiary,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # Collect Policy Reward
    collection_args = ('stake', 'collect-reward', '--config-file',
                       stakeholder_configuration_file_location,
                       '--policy-reward', '--no-staking-reward',
                       '--withdraw-address', burner_wallet.address,
                       '--allocation-filepath',
                       MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Policy Reward
    collected_policy_reward = testerchain.client.get_balance(
        burner_wallet.address)
    expected_collection = policy_rate * 30
    assert collected_policy_reward == expected_collection

    #
    # Collect Staking Reward
    #
    token_agent = ContractAgency.get_agent(agent_class=NucypherTokenAgent,
                                           registry=agency_local_registry)
    balance_before_collecting = token_agent.get_balance(address=staker_address)

    collection_args = ('stake', 'collect-reward', '--config-file',
                       stakeholder_configuration_file_location,
                       '--no-policy-reward', '--staking-reward',
                       '--allocation-filepath',
                       MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # The beneficiary has withdrawn her staking rewards, which are now in the staking contract
    assert token_agent.get_balance(
        address=staker_address) >= balance_before_collecting
Ejemplo n.º 13
0
def test_stake_restake(click_runner, beneficiary, preallocation_escrow_agent,
                       mock_allocation_registry, agency_local_registry,
                       manual_worker, testerchain, individual_allocation,
                       stakeholder_configuration_file_location):

    staker = Staker(is_me=True,
                    checksum_address=beneficiary,
                    registry=agency_local_registry,
                    individual_allocation=individual_allocation)
    assert staker.is_restaking

    restake_args = ('stake', 'restake', '--disable', '--config-file',
                    stakeholder_configuration_file_location,
                    '--allocation-filepath',
                    MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 restake_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    assert not staker.is_restaking
    assert "Successfully disabled" in result.output

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=agency_local_registry)
    current_period = staking_agent.get_current_period()
    release_period = current_period + 1
    lock_args = ('stake', 'restake', '--lock-until', release_period,
                 '--config-file', stakeholder_configuration_file_location,
                 '--allocation-filepath', MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
                 '--force')

    result = click_runner.invoke(nucypher_cli,
                                 lock_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Still not staking and the lock is enabled
    assert not staker.is_restaking
    assert staker.restaking_lock_enabled

    # CLI Output includes success message
    assert "Successfully enabled" in result.output
    assert str(release_period) in result.output

    # Wait until release period
    testerchain.time_travel(periods=1)
    assert not staker.restaking_lock_enabled
    assert not staker.is_restaking

    disable_args = ('stake', 'restake', '--enable', '--config-file',
                    stakeholder_configuration_file_location,
                    '--allocation-filepath',
                    MOCK_INDIVIDUAL_ALLOCATION_FILEPATH, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 disable_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    allocation_contract_address = preallocation_escrow_agent.principal_contract.address
    assert staking_agent.is_restaking(allocation_contract_address)

    staker = Staker(is_me=True,
                    checksum_address=beneficiary,
                    registry=agency_local_registry,
                    individual_allocation=individual_allocation)
    assert staker.is_restaking
    assert "Successfully enabled" in result.output
Ejemplo n.º 14
0
    def create_actor(
        self,
        emitter: StdoutEmitter,
        is_multisig: bool = False
    ) -> Tuple[ContractAdministrator, str, BlockchainInterface,
               BaseContractRegistry]:

        ensure_config_root(self.config_root)
        deployer_interface = initialize_deployer_interface(
            poa=self.poa,
            provider_uri=self.provider_uri,
            emitter=emitter,
            ignore_solidity_check=self.ignore_solidity_check,
            gas_strategy=self.gas_strategy,
            max_gas_price=self.max_gas_price)

        # Warnings
        deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)

        #
        # Establish Registry
        #

        local_registry = establish_deployer_registry(
            emitter=emitter,
            use_existing_registry=bool(
                self.contract_name),  # TODO: Issue #2314
            registry_infile=self.registry_infile,
            registry_outfile=self.registry_outfile,
            dev=self.dev,
            network=self.network)
        #
        # Make Authenticated Deployment Actor
        #

        # Verify Address & collect password
        if is_multisig:
            multisig_agent = ContractAgency.get_agent(MultiSigAgent,
                                                      registry=local_registry)
            deployer_address = multisig_agent.contract.address
            transacting_power = None

        else:
            testnet = deployer_interface.client.chain_name != PUBLIC_CHAINS[
                1]  # Mainnet
            signer = Signer.from_signer_uri(self.signer_uri, testnet=testnet)
            deployer_address = self.deployer_address
            if not deployer_address:
                deployer_address = select_client_account(
                    emitter=emitter,
                    prompt=SELECT_DEPLOYER_ACCOUNT,
                    registry=local_registry,
                    provider_uri=self.provider_uri,
                    signer=signer,
                    show_eth_balance=True)

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

            # Authenticate
            is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri)
            password_required = all(
                (not is_clef, not signer.is_device(account=deployer_address),
                 not deployer_interface.client.is_local, not self.hw_wallet))
            if password_required:
                password = get_client_password(
                    checksum_address=deployer_address)
                signer.unlock_account(password=password,
                                      account=deployer_address)
            transacting_power = TransactingPower(signer=signer,
                                                 account=deployer_address)

        # Produce Actor
        ADMINISTRATOR = ContractAdministrator(
            registry=local_registry,
            domain=self.network,
            transacting_power=transacting_power)

        # Verify ETH Balance
        emitter.echo(
            DEPLOYER_BALANCE.format(eth_balance=ADMINISTRATOR.eth_balance))
        if transacting_power and ADMINISTRATOR.eth_balance == 0:
            emitter.echo(DEPLOYER_ADDRESS_ZERO_ETH, color='red', bold=True)
            raise click.Abort()
        return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
Ejemplo n.º 15
0
def test_get_base_deposit_rate(agency, token_economics, test_registry):
    agent = ContractAgency.get_agent(WorkLockAgent, registry=test_registry)
    base_deposit_rate = agent.get_base_deposit_rate()
    assert base_deposit_rate == token_economics.minimum_allowed_locked / token_economics.worklock_min_allowed_bid
def test_deploy_ethereum_contracts(testerchain, deployment_progress,
                                   test_registry):
    testerchain = testerchain

    origin, *everybody_else = testerchain.client.accounts

    #
    # Nucypher Token
    #
    token_deployer = NucypherTokenDeployer(registry=test_registry,
                                           deployer_address=origin)
    assert token_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert token_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not token_deployer.is_deployed

    token_deployer.deploy(progress=deployment_progress)
    assert token_deployer.is_deployed
    assert len(token_deployer.contract_address) == 42

    token_agent = NucypherTokenAgent(registry=test_registry)
    assert len(token_agent.contract_address) == 42
    assert token_agent.contract_address == token_deployer.contract_address

    another_token_agent = token_deployer.make_agent()
    assert len(another_token_agent.contract_address) == 42
    assert another_token_agent.contract_address == token_deployer.contract_address == token_agent.contract_address

    #
    # StakingEscrow
    #
    stakers_escrow_secret = os.urandom(DispatcherDeployer._secret_length)
    staking_escrow_deployer = StakingEscrowDeployer(registry=test_registry,
                                                    deployer_address=origin)
    assert staking_escrow_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert staking_escrow_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not staking_escrow_deployer.is_deployed

    staking_escrow_deployer.deploy(secret_hash=keccak(stakers_escrow_secret),
                                   progress=deployment_progress)
    assert staking_escrow_deployer.is_deployed
    assert len(staking_escrow_deployer.contract_address) == 42

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=test_registry)
    assert len(staking_agent.contract_address) == 42
    assert staking_agent.contract_address == staking_escrow_deployer.contract_address

    another_staking_agent = staking_escrow_deployer.make_agent()
    assert len(another_staking_agent.contract_address) == 42
    assert another_staking_agent.contract_address == staking_escrow_deployer.contract_address == staking_agent.contract_address

    #
    # Policy Manager
    #
    policy_manager_secret = os.urandom(DispatcherDeployer._secret_length)
    policy_manager_deployer = PolicyManagerDeployer(registry=test_registry,
                                                    deployer_address=origin)

    assert policy_manager_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert policy_manager_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not policy_manager_deployer.is_deployed

    policy_manager_deployer.deploy(secret_hash=keccak(policy_manager_secret),
                                   progress=deployment_progress)
    assert policy_manager_deployer.is_deployed
    assert len(policy_manager_deployer.contract_address) == 42

    policy_agent = policy_manager_deployer.make_agent()
    assert len(policy_agent.contract_address) == 42
    assert policy_agent.contract_address == policy_manager_deployer.contract_address

    another_policy_agent = policy_manager_deployer.make_agent()
    assert len(another_policy_agent.contract_address) == 42
    assert another_policy_agent.contract_address == policy_manager_deployer.contract_address == policy_agent.contract_address

    #
    # Adjudicator
    #
    adjudicator_secret = os.urandom(DispatcherDeployer._secret_length)
    adjudicator_deployer = AdjudicatorDeployer(registry=test_registry,
                                               deployer_address=origin)

    assert adjudicator_deployer.deployer_address == origin

    with pytest.raises(BaseContractDeployer.ContractDeploymentError):
        assert adjudicator_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
    assert not adjudicator_deployer.is_deployed

    adjudicator_deployer.deploy(secret_hash=keccak(adjudicator_secret),
                                progress=deployment_progress)
    assert adjudicator_deployer.is_deployed
    assert len(adjudicator_deployer.contract_address) == 42

    adjudicator_agent = adjudicator_deployer.make_agent()
    assert len(adjudicator_agent.contract_address) == 42
    assert adjudicator_agent.contract_address == adjudicator_deployer.contract_address

    another_adjudicator_agent = AdjudicatorAgent(registry=test_registry)
    assert len(another_adjudicator_agent.contract_address) == 42
    assert another_adjudicator_agent.contract_address == adjudicator_deployer.contract_address == adjudicator_agent.contract_address

    # overall deployment steps must match aggregated individual expected number of steps
    all_deployment_transactions = token_deployer.deployment_steps + staking_escrow_deployer.deployment_steps + \
                                  policy_manager_deployer.deployment_steps + adjudicator_deployer.deployment_steps
    assert deployment_progress.num_steps == len(all_deployment_transactions)
Ejemplo n.º 17
0
def test_create_worklock_agent(testerchain, test_registry, agency, token_economics):
    agent = WorkLockAgent(registry=test_registry)
    assert agent.contract_address
    same_agent = ContractAgency.get_agent(WorkLockAgent, registry=test_registry)
    assert agent == same_agent
    assert not agent.is_claiming_available()
Ejemplo n.º 18
0
def bid(general_config, worklock_options, force, hw_wallet, value):
    """Place a bid, or increase an existing bid"""
    emitter, registry, blockchain = worklock_options.setup(
        general_config=general_config)
    worklock_agent = ContractAgency.get_agent(
        WorkLockAgent, registry=registry)  # type: WorkLockAgent
    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=worklock_options.provider_uri,
            poa=worklock_options.poa,
            network=worklock_options.network,
            registry=registry,
            show_eth_balance=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
Ejemplo n.º 19
0
def test_early_claim(testerchain, agency, token_economics, test_registry):
    agent = ContractAgency.get_agent(WorkLockAgent, registry=test_registry)
    bidder = testerchain.client.accounts[0]
    with pytest.raises(TransactionFailed):
        _receipt = agent.claim(checksum_address=bidder)
Ejemplo n.º 20
0
def claim(general_config, worklock_options, force, hw_wallet):
    """Claim tokens for your bid, and start staking them"""
    emitter, registry, blockchain = worklock_options.setup(
        general_config=general_config)
    worklock_agent = ContractAgency.get_agent(
        WorkLockAgent, registry=registry)  # type: WorkLockAgent
    if not worklock_agent.is_claiming_available():
        raise click.Abort(
            f"You can't claim tokens. Claiming is not currently available.")

    if not worklock_options.bidder_address:
        worklock_options.bidder_address = select_client_account(
            emitter=emitter,
            provider_uri=worklock_options.provider_uri,
            poa=worklock_options.poa,
            network=worklock_options.network,
            registry=registry,
            show_eth_balance=True)

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

    unspent_bid = bidder.available_compensation
    if unspent_bid:
        emitter.echo(
            f"Note that WorkLock did not use your entire bid due to a maximum claim limit.\n"
            f"Therefore, an unspent amount of {prettify_eth_amount(unspent_bid)} is available for refund."
        )
        if not force:
            click.confirm(
                f"Before claiming your NU tokens for {worklock_options.bidder_address}, you will need to be refunded your unspent bid amount. Would you like to proceed?",
                abort=True)
        emitter.echo("Requesting refund of unspent bid amount...")
        receipt = bidder.withdraw_compensation()
        paint_receipt_summary(
            receipt=receipt,
            emitter=emitter,
            chain_name=bidder.staking_agent.blockchain.client.chain_name)

    has_claimed = bidder._has_claimed
    if has_claimed:
        emitter.echo(f"Claim was already done for {bidder.checksum_address}",
                     color='red')
        return

    tokens = NU.from_nunits(bidder.available_claim)
    emitter.echo(f"\nYou have an available claim of {tokens} 🎉 \n",
                 color='green',
                 bold=True)
    if not force:
        lock_duration = bidder.worklock_agent.worklock_parameters()[-2]
        emitter.echo(
            f"Note: Claiming WorkLock NU tokens will initialize a new stake to be locked for {lock_duration} periods.",
            color='blue')
        click.confirm(
            f"Continue WorkLock claim for bidder {worklock_options.bidder_address}?",
            abort=True)
    emitter.echo("Submitting Claim...")

    receipt = bidder.claim()
    paint_receipt_summary(
        receipt=receipt,
        emitter=emitter,
        chain_name=bidder.staking_agent.blockchain.client.chain_name)
    paint_worklock_claim(emitter=emitter,
                         bidder_address=worklock_options.bidder_address,
                         network=worklock_options.network,
                         provider_uri=worklock_options.provider_uri)
    return  # Exit
Ejemplo n.º 21
0
    def create_actor(
        self,
        emitter: StdoutEmitter,
        is_multisig: bool = False
    ) -> Tuple[ContractAdministrator, str, BlockchainInterface,
               BaseContractRegistry]:

        ensure_config_root(self.config_root)
        deployer_interface = initialize_deployer_interface(
            poa=self.poa,
            provider_uri=self.provider_uri,
            emitter=emitter,
            ignore_solidity_check=self.ignore_solidity_check,
            gas_strategy=self.gas_strategy)

        # Warnings
        deployer_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)

        #
        # Establish Registry
        #
        local_registry = establish_deployer_registry(
            emitter=emitter,
            use_existing_registry=bool(self.contract_name),
            registry_infile=self.registry_infile,
            registry_outfile=self.registry_outfile,
            dev=self.dev)
        #
        # Make Authenticated Deployment Actor
        #
        # Verify Address & collect password
        password = None
        if is_multisig:
            multisig_agent = ContractAgency.get_agent(MultiSigAgent,
                                                      registry=local_registry)
            deployer_address = multisig_agent.contract.address
            is_transacting = False
        else:
            is_transacting = True
            deployer_address = self.deployer_address
            if not deployer_address:
                deployer_address = select_client_account(
                    emitter=emitter,
                    prompt=SELECT_DEPLOYER_ACCOUNT,
                    provider_uri=self.provider_uri,
                    signer_uri=self.signer_uri,
                    show_eth_balance=True)

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

            is_clef = ClefSigner.is_valid_clef_uri(self.signer_uri)
            eth_password_is_needed = not self.hw_wallet and not deployer_interface.client.is_local and not is_clef
            if eth_password_is_needed:
                password = get_client_password(
                    checksum_address=deployer_address)
        # Produce Actor
        signer = Signer.from_signer_uri(
            self.signer_uri) if self.signer_uri else None
        ADMINISTRATOR = ContractAdministrator(
            registry=local_registry,
            client_password=password,
            deployer_address=deployer_address,
            is_transacting=is_transacting,
            signer=signer,
            staking_escrow_test_mode=self.se_test_mode)
        # Verify ETH Balance
        emitter.echo(
            DEPLOYER_BALANCE.format(eth_balance=ADMINISTRATOR.eth_balance))
        if is_transacting and ADMINISTRATOR.eth_balance == 0:
            emitter.echo(DEPLOYER_ADDRESS_ZERO_ETH, color='red', bold=True)
            raise click.Abort()
        return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
Ejemplo n.º 22
0
def paint_stakers(emitter, stakers: List[str],
                  registry: BaseContractRegistry) -> None:
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=registry)
    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_address in stakers:
        staker = Staker(is_me=False,
                        checksum_address=staker_address,
                        registry=registry)
        nickname = Nickname.from_seed(staker_address)
        emitter.echo(
            f"{staker_address}  {'Nickname:':10} {nickname} {nickname.icon}")
        tab = " " * len(staker_address)

        owned_tokens = staker.owned_tokens()
        last_committed_period = staker.last_committed_period
        worker = staker.worker_address
        is_restaking = staker.is_restaking
        is_winding_down = staker.is_winding_down
        is_taking_snapshots = staker.is_taking_snapshots

        missing_commitments = current_period - last_committed_period
        owned_in_nu = round(owned_tokens, 2)
        current_locked_tokens = round(staker.locked_tokens(periods=0), 2)
        next_locked_tokens = round(staker.locked_tokens(periods=1), 2)

        emitter.echo(f"{tab}  {'Owned:':10} {owned_in_nu}")
        emitter.echo(
            f"{tab}  Staked in current period: {current_locked_tokens}")
        emitter.echo(f"{tab}  Staked in next period: {next_locked_tokens}")
        if is_restaking:
            if staker.restaking_lock_enabled:
                unlock_period = staker.restake_unlock_period
                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}  {'Snapshots:':10} {'Yes' if is_taking_snapshots else 'No'}"
        )
        emitter.echo(f"{tab}  {'Activity:':10} ", nl=False)
        if missing_commitments == -1:
            emitter.echo(f"Next period committed (#{last_committed_period})",
                         color='green')
        elif missing_commitments == 0:
            emitter.echo(
                f"Current period committed (#{last_committed_period}). "
                f"Pending commitment to next period.",
                color='yellow')
        elif missing_commitments == current_period:
            emitter.echo(f"Never made a commitment", color='red')
        else:
            emitter.echo(
                f"Missing {missing_commitments} commitments "
                f"(last time for period #{last_committed_period})",
                color='red')

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

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

        min_rate = prettify_eth_amount(staker.min_fee_rate)
        emitter.echo(f"{tab}  Min fee rate: {min_rate}")
def test_stake_restake(click_runner,
                       manual_staker,
                       custom_filepath,
                       testerchain,
                       agency_local_registry,
                       stakeholder_configuration_file_location):

    staker = Staker(is_me=True, checksum_address=manual_staker, registry=agency_local_registry)
    assert staker.is_restaking

    restake_args = ('stake', 'restake',
                    '--disable',
                    '--config-file', stakeholder_configuration_file_location,
                    '--staking-address', manual_staker,
                    '--force')

    result = click_runner.invoke(nucypher_cli,
                                 restake_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    assert not staker.is_restaking
    assert "Successfully disabled" in result.output

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=agency_local_registry)
    current_period = staking_agent.get_current_period()
    release_period = current_period + 1
    lock_args = ('stake', 'restake',
                 '--lock-until', release_period,
                 '--config-file', stakeholder_configuration_file_location,
                 '--staking-address', manual_staker,
                 '--force')

    result = click_runner.invoke(nucypher_cli,
                                 lock_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Still not staking and the lock is enabled
    assert not staker.is_restaking
    assert staker.restaking_lock_enabled

    # CLI Output includes success message
    assert "Successfully enabled" in result.output
    assert str(release_period) in result.output

    # Wait until release period
    testerchain.time_travel(periods=1)
    assert not staker.restaking_lock_enabled
    assert not staker.is_restaking

    disable_args = ('stake', 'restake',
                    '--enable',
                    '--config-file', stakeholder_configuration_file_location,
                    '--staking-address', manual_staker,
                    '--force')

    result = click_runner.invoke(nucypher_cli,
                                 disable_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    assert staker.is_restaking
    assert "Successfully enabled" in result.output

    # Disable again
    disable_args = ('stake', 'restake',
                    '--disable',
                    '--config-file', stakeholder_configuration_file_location,
                    '--staking-address', manual_staker,
                    '--force')

    result = click_runner.invoke(nucypher_cli,
                                 disable_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0
Ejemplo n.º 24
0
def test_adjudicator_slashes(agency,
                             testerchain,
                             mock_ursula_reencrypts,
                             token_economics,
                             test_registry,
                             mocker):

    staker_account = testerchain.staker_account(0)
    worker_account = testerchain.ursula_account(0)

    ##### STAKING ESCROW STUFF #####

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

    locked_tokens = token_economics.minimum_allowed_locked * 5

    # The staker receives an initial amount of tokens
    tpower = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client))
    _txhash = token_agent.transfer(amount=locked_tokens,
                                   target_address=staker_account,
                                   transacting_power=tpower)

    # Deposit: The staker deposits tokens in the StakingEscrow contract.
    tpower = TransactingPower(account=staker_account, signer=Web3Signer(testerchain.client))
    staker = Staker(domain=TEMPORARY_DOMAIN,
                    registry=test_registry,
                    transacting_power=tpower)

    staker.initialize_stake(amount=NU(locked_tokens, 'NuNit'),
                            lock_periods=token_economics.minimum_locked_periods)
    assert staker.locked_tokens(periods=1) == locked_tokens

    # The staker hasn't bond a worker yet
    assert NULL_ADDRESS == staking_agent.get_worker_from_staker(staker_address=staker_account)

    _txhash = staking_agent.bond_worker(transacting_power=tpower, worker_address=worker_account)

    assert worker_account == staking_agent.get_worker_from_staker(staker_address=staker_account)
    assert staker_account == staking_agent.get_staker_from_worker(worker_address=worker_account)

    ###### END OF STAKING ESCROW STUFF ####

    adjudicator_agent = AdjudicatorAgent(registry=test_registry)
    bob_account = testerchain.bob_account
    bobby = NucypherTokenActor(checksum_address=bob_account,
                               domain=TEMPORARY_DOMAIN,
                               registry=test_registry)
    ursula = mock_ursula(testerchain, worker_account, mocker=mocker)

    # Let's create a bad cfrag
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)

    assert not adjudicator_agent.was_this_evidence_evaluated(evidence)
    bobby_old_balance = bobby.token_balance
    bob_tpower = TransactingPower(account=bob_account, signer=Web3Signer(testerchain.client))

    adjudicator_agent.evaluate_cfrag(evidence=evidence, transacting_power=bob_tpower)

    assert adjudicator_agent.was_this_evidence_evaluated(evidence)
    investigator_reward = bobby.token_balance - bobby_old_balance

    assert investigator_reward > 0
    assert investigator_reward == token_economics.base_penalty / token_economics.reward_coefficient
    assert staker.locked_tokens(periods=1) < locked_tokens
Ejemplo n.º 25
0
    def create_actor(self, emitter, is_multisig: bool = False):

        _ensure_config_root(self.config_root)
        deployer_interface = _initialize_blockchain(
            poa=self.poa,
            provider_uri=self.provider_uri,
            emitter=emitter,
            ignore_solidity_check=self.ignore_solidity_check,
            gas_strategy=self.gas_strategy)

        # Warnings
        _pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)

        #
        # Establish Registry
        #
        local_registry = establish_deployer_registry(
            emitter=emitter,
            use_existing_registry=bool(self.contract_name),
            registry_infile=self.registry_infile,
            registry_outfile=self.registry_outfile,
            dev=self.dev)
        #
        # Make Authenticated Deployment Actor
        #
        # Verify Address & collect password
        password = None
        if is_multisig:
            multisig_agent = ContractAgency.get_agent(MultiSigAgent,
                                                      registry=local_registry)
            deployer_address = multisig_agent.contract.address
            is_transacting = False
        else:
            is_transacting = True
            deployer_address = self.deployer_address
            if not deployer_address:
                prompt = "Select deployer account"
                deployer_address = select_client_account(
                    emitter=emitter,
                    prompt=prompt,
                    provider_uri=self.provider_uri,
                    signer_uri=self.signer_uri,
                    show_eth_balance=True)

            if not self.force:
                click.confirm(
                    "Selected {} - Continue?".format(deployer_address),
                    abort=True)

            if not self.hw_wallet and not deployer_interface.client.is_local:
                password = get_client_password(
                    checksum_address=deployer_address)
        # Produce Actor
        signer = Signer.from_signer_uri(
            self.signer_uri) if self.signer_uri else None
        ADMINISTRATOR = ContractAdministrator(
            registry=local_registry,
            client_password=password,
            deployer_address=deployer_address,
            is_transacting=is_transacting,
            signer=signer,
            staking_escrow_test_mode=self.se_test_mode)
        # Verify ETH Balance
        emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}")
        if is_transacting and ADMINISTRATOR.eth_balance == 0:
            emitter.echo("Deployer address has no ETH.",
                         color='red',
                         bold=True)
            raise click.Abort()
        return ADMINISTRATOR, deployer_address, deployer_interface, local_registry
Ejemplo n.º 26
0
def events(general_config, registry_options, contract_name, from_block,
           to_block, event_name, csv, csv_file, event_filters):
    """Show events associated with NuCypher contracts."""

    if csv or csv_file:
        if csv and csv_file:
            raise click.BadOptionUsage(
                option_name='--event-filter',
                message=f'Pass either --csv or --csv-file, not both.')

        # ensure that event name is specified - different events would have different columns in the csv file
        if csv_file and not all((event_name, contract_name)):
            # TODO consider a single csv that just gets appended to for each event
            #  - each appended event adds their column names first
            #  - single report-type functionality, see #2561
            raise click.BadOptionUsage(
                option_name='--csv-file, --event-name, --contract_name',
                message=
                '--event-name and --contract-name must be specified when outputting to '
                'specific file using --csv-file; alternatively use --csv')
    if not contract_name:
        if event_name:
            raise click.BadOptionUsage(
                option_name='--event-name',
                message='--event-name requires --contract-name')
        # FIXME should we force a contract name to be specified?
        contract_names = [
            STAKING_ESCROW_CONTRACT_NAME, POLICY_MANAGER_CONTRACT_NAME
        ]
    else:
        contract_names = [contract_name]

    emitter, registry, blockchain = registry_options.setup(
        general_config=general_config)

    if from_block is None:
        # by default, this command only shows events of the current period
        last_block = blockchain.client.block_number
        staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                                 registry=registry)
        current_period = staking_agent.get_current_period()
        from_block = estimate_block_number_for_period(
            period=current_period,
            seconds_per_period=staking_agent.staking_parameters()[1],
            latest_block=last_block)
    if to_block is None:
        to_block = 'latest'
    else:
        # validate block range
        if from_block > to_block:
            raise click.BadOptionUsage(
                option_name='--to-block, --from-block',
                message=f'Invalid block range provided, '
                f'from-block ({from_block}) > to-block ({to_block})')

    # event argument filters
    argument_filters = None
    if event_filters:
        try:
            argument_filters = parse_event_filters_into_argument_filters(
                event_filters)
        except ValueError as e:
            raise click.BadOptionUsage(
                option_name='--event-filter',
                message=f'Event filter must be specified as name-value pairs of '
                f'the form `<name>=<value>` - {str(e)}')

    emitter.echo(f"Retrieving events from block {from_block} to {to_block}")
    for contract_name in contract_names:
        agent = ContractAgency.get_agent_by_contract_name(
            contract_name, registry)
        if event_name and event_name not in agent.events.names:
            raise click.BadOptionUsage(
                option_name='--event-name, --contract_name',
                message=
                f'{contract_name} contract does not have an event named {event_name}'
            )

        title = f" {agent.contract_name} Events ".center(40, "-")
        emitter.echo(f"\n{title}\n", bold=True, color='green')
        names = agent.events.names if not event_name else [event_name]
        for name in names:
            # csv output file - one per (contract_name, event_name) pair
            csv_output_file = csv_file
            if csv or csv_output_file:
                if not csv_output_file:
                    csv_output_file = generate_events_csv_file(
                        contract_name=agent.contract_name, event_name=name)

            retrieve_events(
                emitter=emitter,
                agent=agent,
                event_name=name,  # None is fine - just means all events
                from_block=from_block,
                to_block=to_block,
                argument_filters=argument_filters,
                csv_output_file=csv_output_file)
Ejemplo n.º 27
0
def paint_deployer_contract_inspection(emitter, registry, deployer_address) -> None:

    blockchain = BlockchainInterfaceFactory.get_interface()

    sep = '-' * 45
    emitter.echo(sep)

    provider_info = f"""

* Web3 Provider
====================================================================

Provider URI ............. {blockchain.provider_uri}
Registry  ................ {registry.filepath}

* Standard Deployments
=====================================================================
"""
    emitter.echo(provider_info)

    try:
        token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=registry)
        token_contract_info = f"""

{token_agent.contract_name} ........... {token_agent.contract_address}
    ~ Ethers ............ {Web3.fromWei(blockchain.client.get_balance(token_agent.contract_address), 'ether')} ETH
    ~ Tokens ............ {NU.from_nunits(token_agent.get_balance(token_agent.contract_address))}"""
    except BaseContractRegistry.UnknownContract:
        message = f"\n{NucypherTokenAgent.contract_name} is not enrolled in {registry.filepath}"
        emitter.echo(message, color='yellow')
        emitter.echo(sep, nl=False)
    else:
        emitter.echo(token_contract_info)

    banner = """
* Proxy-Contract Deployments
====================================================================="""
    emitter.echo(banner)

    from nucypher.blockchain.eth.actors import ContractAdministrator
    for contract_deployer_class in ContractAdministrator.dispatched_upgradeable_deployer_classes:
        try:
            bare_contract = blockchain.get_contract_by_name(contract_name=contract_deployer_class.contract_name,
                                                            proxy_name=DispatcherDeployer.contract_name,
                                                            registry=registry,
                                                            use_proxy_address=False)

            dispatcher_deployer = DispatcherDeployer(registry=registry,
                                                     target_contract=bare_contract,
                                                     deployer_address=deployer_address,
                                                     bare=True)  # acquire agency for the dispatcher itself.

            agent = contract_deployer_class.agency(registry=registry, contract=bare_contract)

            proxy_payload = f"""
{agent.contract_name} .... {bare_contract.address}
    ~ Owner .............. {bare_contract.functions.owner().call()}
    ~ Ethers ............. {Web3.fromWei(blockchain.client.get_balance(bare_contract.address), 'ether')} ETH
    ~ Tokens ............. {NU.from_nunits(token_agent.get_balance(bare_contract.address))}
    ~ Dispatcher ......... {dispatcher_deployer.contract_address}
        ~ Owner .......... {dispatcher_deployer.contract.functions.owner().call()}
        ~ Target ......... {dispatcher_deployer.contract.functions.target().call()}
        ~ Ethers ......... {Web3.fromWei(blockchain.client.get_balance(dispatcher_deployer.contract_address), 'ether')} ETH
        ~ Tokens ......... {NU.from_nunits(token_agent.get_balance(dispatcher_deployer.contract_address))}"""
            emitter.echo(proxy_payload)
            emitter.echo(sep, nl=False)

        except BaseContractRegistry.UnknownContract:
            message = f"\n{contract_deployer_class.contract_name} is not enrolled in {registry.filepath}"
            emitter.echo(message, color='yellow')
            emitter.echo(sep, nl=False)

    try:

        #
        # StakingInterface
        #

        staking_interface_agent = PreallocationEscrowAgent.StakingInterfaceAgent(registry=registry)
        bare_contract = blockchain.get_contract_by_name(contract_name=staking_interface_agent.contract_name,
                                                        proxy_name=StakingInterfaceRouterDeployer.contract_name,
                                                        use_proxy_address=False,
                                                        registry=registry)

        router_deployer = StakingInterfaceRouterDeployer(registry=registry,
                                                         target_contract=bare_contract,
                                                         deployer_address=deployer_address,
                                                         bare=True)  # acquire agency for the dispatcher itself.

        preallocation_escrow_payload = f"""
{staking_interface_agent.contract_name} ......... {bare_contract.address}
  ~ Ethers ............... {Web3.fromWei(blockchain.client.get_balance(bare_contract.address), 'ether')} ETH
  ~ Tokens ............... {NU.from_nunits(token_agent.get_balance(bare_contract.address))}
  ~ StakingInterfaceRouter {router_deployer.contract.address}
        ~ Owner .......... {router_deployer.contract.functions.owner().call()}
        ~ Target ......... {router_deployer.contract.functions.target().call()}
        ~ Ethers ......... {Web3.fromWei(blockchain.client.get_balance(router_deployer.contract_address), 'ether')} ETH
        ~ Tokens ......... {NU.from_nunits(token_agent.get_balance(router_deployer.contract_address))}"""
        emitter.echo(preallocation_escrow_payload)
        emitter.echo(sep)

    except BaseContractRegistry.UnknownContract:
        message = f"\nStakingInterface is not enrolled in {registry.filepath}"
        emitter.echo(message, color='yellow')
Ejemplo n.º 28
0
def create_staking_events_metric_collectors(ursula: 'Ursula', metrics_prefix: str) -> List[MetricsCollector]:
    """Create collectors for staking-related events."""
    collectors: List[MetricsCollector] = []
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=ursula.registry)

    staker_address = ursula.checksum_address

    # CommitmentMade
    collectors.append(CommitmentMadeEventMetricsCollector(
        event_args_config={
            "value": (Gauge,
                      f'{metrics_prefix}_activity_confirmed_value',
                      'CommitmentMade to next period with value of locked tokens'),
            "period": (Gauge, f'{metrics_prefix}_activity_confirmed_period', 'Commitment made for period')
        },
        staker_address=staker_address,
        contract_agent=staking_agent))

    # Minted
    collectors.append(EventMetricsCollector(
        event_name='Minted',
        event_args_config={
            "value": (Gauge, f'{metrics_prefix}_mined_value', 'Minted value'),
            "period": (Gauge, f'{metrics_prefix}_mined_period', 'Minted period'),
            "block_number": (Gauge, f'{metrics_prefix}_mined_block_number', 'Minted block number')
        },
        argument_filters={'staker': staker_address},
        contract_agent=staking_agent))

    # Slashed
    collectors.append(EventMetricsCollector(
        event_name='Slashed',
        event_args_config={
            "penalty": (Gauge, f'{metrics_prefix}_last_slashed_penalty', 'Penalty for slashing'),
            "block_number": (Gauge,
                             f'{metrics_prefix}_last_slashed_penalty_block_number',
                             'Slashed penalty block number')
        },
        argument_filters={'staker': staker_address},
        contract_agent=staking_agent))

    # RestakeSet
    collectors.append(ReStakeEventMetricsCollector(
        event_args_config={
            "reStake": (Gauge, f'{metrics_prefix}_restaking', 'Restake set')
        },
        staker_address=staker_address,
        contract_agent=staking_agent))

    # WindDownSet
    collectors.append(WindDownEventMetricsCollector(
        event_args_config={
            "windDown": (Gauge, f'{metrics_prefix}_wind_down', 'is windDown')
        },
        staker_address=staker_address,
        contract_agent=staking_agent))

    # WorkerBonded
    collectors.append(WorkerBondedEventMetricsCollector(
        event_args_config={
            "startPeriod": (Gauge, f'{metrics_prefix}_worker_set_start_period', 'New worker was bonded'),
            "block_number": (Gauge, f'{metrics_prefix}_worker_set_block_number', 'WorkerBonded block number')
        },
        staker_address=staker_address,
        worker_address=ursula.worker_address,
        contract_agent=staking_agent))

    return collectors
Ejemplo n.º 29
0
def deploy(action, poa, etherscan, provider_uri, gas, deployer_address,
           contract_name, allocation_infile, allocation_outfile,
           registry_infile, registry_outfile, value, target_address, retarget,
           bare, config_root, hw_wallet, force, dev):
    """
    Manage contract and registry deployment.

    \b
    Actions
    -----------------------------------------------------------------------------
    contracts              Compile and deploy contracts.
    allocations            Deploy pre-allocation contracts.
    upgrade                Upgrade NuCypher existing proxy contract deployments.
    rollback               Rollback a proxy contract's target.
    inspect                Echo owner information and bare contract metadata.
    transfer-tokens        Transfer tokens from a contract to another address using the owner's address.
    transfer-ownership     Transfer ownership of contracts to another address.
    """

    emitter = StdoutEmitter()

    #
    # Validate
    #

    # Ensure config root exists, because we need a default place to put output files.
    config_root = config_root or DEFAULT_CONFIG_ROOT
    if not os.path.exists(config_root):
        os.makedirs(config_root)

    #
    # Pre-Launch Warnings
    #

    if not hw_wallet:
        emitter.echo("WARNING: --no-hw-wallet is enabled.", color='yellow')

    if etherscan:
        emitter.echo(
            "WARNING: --etherscan is enabled. "
            "A browser tab will be opened with deployed contracts and TXs as provided by Etherscan.",
            color='yellow')
    else:
        emitter.echo(
            "WARNING: --etherscan is disabled. "
            "If you want to see deployed contracts and TXs in your browser, activate --etherscan.",
            color='yellow')

    if action == "download-registry":
        if not force:
            prompt = f"Fetch and download latest registry from {BaseContractRegistry.PUBLICATION_ENDPOINT}?"
            click.confirm(prompt, abort=True)
        registry = InMemoryContractRegistry.from_latest_publication()
        output_filepath = registry.commit(filepath=registry_outfile,
                                          overwrite=force)
        emitter.message(
            f"Successfully downloaded latest registry to {output_filepath}")
        return  # Exit

    #
    # Connect to Blockchain
    #

    if not provider_uri:
        raise click.BadOptionUsage(
            message=f"--provider is required to deploy.",
            option_name="--provider")

    if not BlockchainInterfaceFactory.is_interface_initialized(
            provider_uri=provider_uri):
        # Note: For test compatibility.
        deployer_interface = BlockchainDeployerInterface(
            provider_uri=provider_uri, poa=poa)
        BlockchainInterfaceFactory.register_interface(
            interface=deployer_interface, sync=False, show_sync_progress=False)
    else:
        deployer_interface = BlockchainInterfaceFactory.get_interface(
            provider_uri=provider_uri)

    if action == "inspect":
        if registry_infile:
            registry = LocalContractRegistry(filepath=registry_infile)
        else:
            registry = InMemoryContractRegistry.from_latest_publication()
        administrator = ContractAdministrator(
            registry=registry, deployer_address=deployer_address)
        paint_deployer_contract_inspection(emitter=emitter,
                                           administrator=administrator)
        return  # Exit

    #
    # Establish Registry
    #
    local_registry = establish_deployer_registry(
        emitter=emitter,
        use_existing_registry=bool(contract_name),
        registry_infile=registry_infile,
        registry_outfile=registry_outfile,
        dev=dev)

    #
    # Make Authenticated Deployment Actor
    #

    # Verify Address & collect password
    if not deployer_address:
        prompt = "Select deployer account"
        deployer_address = select_client_account(emitter=emitter,
                                                 prompt=prompt,
                                                 provider_uri=provider_uri,
                                                 show_balances=False)

    if not force:
        click.confirm("Selected {} - Continue?".format(deployer_address),
                      abort=True)

    password = None
    if not hw_wallet and not deployer_interface.client.is_local:
        password = get_client_password(checksum_address=deployer_address)

    # Produce Actor
    ADMINISTRATOR = ContractAdministrator(registry=local_registry,
                                          client_password=password,
                                          deployer_address=deployer_address)

    # Verify ETH Balance
    emitter.echo(f"\n\nDeployer ETH balance: {ADMINISTRATOR.eth_balance}")
    if ADMINISTRATOR.eth_balance == 0:
        emitter.echo("Deployer address has no ETH.", color='red', bold=True)
        raise click.Abort()

    #
    # Action switch
    #

    if action == 'upgrade':
        if not contract_name:
            raise click.BadArgumentUsage(
                message="--contract-name is required when using --upgrade")
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)

        if retarget:
            if not target_address:
                raise click.BadArgumentUsage(
                    message="--target-address is required when using --retarget"
                )
            if not force:
                click.confirm(
                    f"Confirm re-target {contract_name}'s proxy to {target_address}?",
                    abort=True)
            receipt = ADMINISTRATOR.retarget_proxy(
                contract_name=contract_name,
                target_address=target_address,
                existing_plaintext_secret=existing_secret,
                new_plaintext_secret=new_secret)
            emitter.message(
                f"Successfully re-targeted {contract_name} proxy to {target_address}",
                color='green')
            paint_receipt_summary(emitter=emitter, receipt=receipt)
            return  # Exit
        else:
            if not force:
                click.confirm(
                    f"Confirm deploy new version of {contract_name} and retarget proxy?",
                    abort=True)
            receipts = ADMINISTRATOR.upgrade_contract(
                contract_name=contract_name,
                existing_plaintext_secret=existing_secret,
                new_plaintext_secret=new_secret)
            emitter.message(
                f"Successfully deployed and upgraded {contract_name}",
                color='green')
            for name, receipt in receipts.items():
                paint_receipt_summary(emitter=emitter, receipt=receipt)
            return  # Exit

    elif action == 'rollback':
        if not contract_name:
            raise click.BadArgumentUsage(
                message="--contract-name is required when using --rollback")
        existing_secret = click.prompt(
            'Enter existing contract upgrade secret', hide_input=True)
        new_secret = click.prompt('Enter new contract upgrade secret',
                                  hide_input=True,
                                  confirmation_prompt=True)
        ADMINISTRATOR.rollback_contract(
            contract_name=contract_name,
            existing_plaintext_secret=existing_secret,
            new_plaintext_secret=new_secret)
        return  # Exit

    elif action == "contracts":

        #
        # Deploy Single Contract (Amend Registry)
        #

        if contract_name:
            try:
                contract_deployer = ADMINISTRATOR.deployers[contract_name]
            except KeyError:
                message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
                emitter.echo(message, color='red', bold=True)
                raise click.Abort()

            # Deploy
            emitter.echo(f"Deploying {contract_name}")
            if contract_deployer._upgradeable and not bare:
                # NOTE: Bare deployments do not engage the proxy contract
                secret = ADMINISTRATOR.collect_deployment_secret(
                    deployer=contract_deployer)
                receipts, agent = ADMINISTRATOR.deploy_contract(
                    contract_name=contract_name,
                    plaintext_secret=secret,
                    gas_limit=gas,
                    bare=bare)
            else:
                # Non-Upgradeable or Bare
                receipts, agent = ADMINISTRATOR.deploy_contract(
                    contract_name=contract_name, gas_limit=gas, bare=bare)

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

        #
        # Deploy Automated Series (Create Registry)
        #

        # Confirm filesystem registry writes.
        if os.path.isfile(local_registry.filepath):
            emitter.echo(
                f"\nThere is an existing contract registry at {local_registry.filepath}.\n"
                f"Did you mean 'nucypher-deploy upgrade'?\n",
                color='yellow')
            click.confirm("*DESTROY* existing local registry and continue?",
                          abort=True)
            os.remove(local_registry.filepath)

        # Stage Deployment
        secrets = ADMINISTRATOR.collect_deployment_secrets()
        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(
            secrets=secrets,
            emitter=emitter,
            interactive=not force,
            etherscan=etherscan)

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

        # Save transaction metadata
        receipts_filepath = ADMINISTRATOR.save_deployment_receipts(
            receipts=deployment_receipts)
        emitter.echo(f"Saved deployment receipts to {receipts_filepath}",
                     color='blue',
                     bold=True)
        return  # Exit

    elif action == "allocations":
        if not allocation_infile:
            allocation_infile = click.prompt("Enter allocation data filepath")
        click.confirm("Continue deploying and allocating?", abort=True)
        ADMINISTRATOR.deploy_beneficiaries_from_file(
            allocation_data_filepath=allocation_infile,
            allocation_outfile=allocation_outfile)
        return  # Exit

    elif action == "transfer-tokens":
        token_agent = ContractAgency.get_agent(NucypherTokenAgent,
                                               registry=local_registry)
        if not target_address:
            target_address = click.prompt("Enter recipient's checksum address",
                                          type=EIP55_CHECKSUM_ADDRESS)
        if not value:
            stake_value_range = click.FloatRange(min=0, clamp=False)
            value = NU.from_tokens(
                click.prompt(f"Enter value in NU", type=stake_value_range))

        click.confirm(
            f"Transfer {value} from {deployer_address} to {target_address}?",
            abort=True)
        receipt = token_agent.transfer(amount=value,
                                       sender_address=deployer_address,
                                       target_address=target_address)
        emitter.echo(f"OK | Receipt: {receipt['transactionHash'].hex()}")
        return  # Exit

    elif action == "transfer-ownership":
        if not target_address:
            target_address = click.prompt("Enter new owner's checksum address",
                                          type=EIP55_CHECKSUM_ADDRESS)

        if contract_name:
            try:
                contract_deployer_class = ADMINISTRATOR.deployers[
                    contract_name]
            except KeyError:
                message = f"No such contract {contract_name}. Available contracts are {ADMINISTRATOR.deployers.keys()}"
                emitter.echo(message, color='red', bold=True)
                raise click.Abort()
            else:
                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)
                emitter.ipc(receipt, request_id=0, duration=0)  # TODO: #1216
                return  # Exit
        else:
            receipts = ADMINISTRATOR.relinquish_ownership(
                new_owner=target_address, transaction_gas_limit=gas)
            emitter.ipc(receipts, request_id=0, duration=0)  # TODO: #1216
            return  # Exit

    else:
        raise click.BadArgumentUsage(message=f"Unknown action '{action}'")
Ejemplo n.º 30
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)