Exemple #1
0
def test_individual_allocation_registry(get_random_checksum_address, test_registry, tempfile_path):
    empty_allocation_escrow_deployer = PreallocationEscrowDeployer(registry=test_registry)
    allocation_contract_abi = empty_allocation_escrow_deployer.get_contract_abi()

    beneficiary = get_random_checksum_address()
    contract_address = get_random_checksum_address()
    allocation_registry = IndividualAllocationRegistry(beneficiary_address=beneficiary,
                                                       contract_address=contract_address)

    registry_data = allocation_registry.read()
    assert len(registry_data) == 1

    assert allocation_registry.search(beneficiary_address=beneficiary) == [contract_address, allocation_contract_abi]
    assert allocation_registry.search(contract_address=contract_address) == [beneficiary, allocation_contract_abi]

    # Check that searching for an unknown beneficiary or unknown contract raises
    with pytest.raises(IndividualAllocationRegistry.UnknownBeneficiary):
        allocation_registry.search(beneficiary_address=get_random_checksum_address())

    with pytest.raises(IndividualAllocationRegistry.UnknownContract):
        allocation_registry.search(contract_address=get_random_checksum_address())

    # Check that it gets the same data if using a file to create the allocation registry
    individual_allocation_file_data = {
        'beneficiary_address': beneficiary,
        'contract_address': contract_address
    }
    with open(tempfile_path, 'w') as outfile:
        json.dump(individual_allocation_file_data, outfile)

    allocation_registry = IndividualAllocationRegistry.from_allocation_file(filepath=tempfile_path)
    assert registry_data == allocation_registry.read()
Exemple #2
0
def test_deploy_multiple_preallocations(testerchain, test_registry):

    deployer_account = testerchain.etherbase_account

    router = testerchain.get_contract_by_name(
        registry=test_registry,
        contract_name=StakingInterfaceRouterDeployer.contract_name)
    router_address = router.address
    for index in range(NUMBER_OF_PREALLOCATIONS):
        deployer = PreallocationEscrowDeployer(
            deployer_address=deployer_account, registry=test_registry)

        deployment_receipt = deployer.deploy()
        assert deployment_receipt['status'] == 1

        preallocation_escrow_contract = deployer.contract
        router = preallocation_escrow_contract.functions.router().call()
        assert router == router_address

        preallocation_escrow_contracts.append(preallocation_escrow_contract)

        # simulates passage of time / blocks
        if index % 5 == 0:
            testerchain.w3.eth.web3.testing.mine(1)
            testerchain.time_travel(seconds=5)

    assert len(preallocation_escrow_contracts) == NUMBER_OF_PREALLOCATIONS
def agent(testerchain, test_registry, allocation_value, agency,
          mock_transacting_power_activation) -> PreallocationEscrowAgent:
    deployer_address, beneficiary_address, *everybody_else = testerchain.client.accounts

    escrow_deployer = PreallocationEscrowDeployer(deployer_address=deployer_address,
                                                  registry=test_registry,
                                                  allocation_registry=TEST_ALLOCATION_REGISTRY)

    mock_transacting_power_activation(account=deployer_address, password=INSECURE_DEVELOPMENT_PASSWORD)
    _receipt = escrow_deployer.deploy()

    escrow_deployer.initial_deposit(value=allocation_value, duration_seconds=TEST_LOCK_DURATION_IN_SECONDS)
    assert escrow_deployer.contract.functions.getLockedTokens().call() == allocation_value
    escrow_deployer.assign_beneficiary(checksum_address=beneficiary_address)
    escrow_deployer.enroll_principal_contract()
    assert escrow_deployer.contract.functions.getLockedTokens().call() == allocation_value
    agent = escrow_deployer.make_agent()

    direct_agent = PreallocationEscrowAgent(registry=test_registry,
                                            allocation_registry=TEST_ALLOCATION_REGISTRY,
                                            beneficiary=beneficiary_address)

    assert direct_agent == agent
    assert direct_agent.contract.abi == agent.contract.abi
    assert direct_agent.contract.address == agent.contract.address
    assert agent.principal_contract.address == escrow_deployer.contract.address
    assert agent.principal_contract.abi == escrow_deployer.contract.abi
    assert direct_agent.contract.abi == escrow_deployer.contract.abi
    assert direct_agent.contract.address == escrow_deployer.contract.address

    yield agent
    TEST_ALLOCATION_REGISTRY.clear()
Exemple #4
0
 def deploy_preallocation_escrow(self, allocation_registry: AllocationRegistry, progress=None) -> PreallocationEscrowDeployer:
     preallocation_escrow_deployer = PreallocationEscrowDeployer(registry=self.registry,
                                                                 deployer_address=self.deployer_address,
                                                                 allocation_registry=allocation_registry)
     preallocation_escrow_deployer.deploy(progress=progress)
     principal_address = preallocation_escrow_deployer.contract.address
     self.preallocation_escrow_deployers[principal_address] = preallocation_escrow_deployer
     return preallocation_escrow_deployer
Exemple #5
0
def mock_allocation_registry(testerchain, agency_local_registry, token_economics):
    # Deploy the PreallocationEscrow contract
    allocation_registry = InMemoryAllocationRegistry()
    deployer = PreallocationEscrowDeployer(deployer_address=testerchain.etherbase_account,
                                           registry=agency_local_registry,
                                           allocation_registry=allocation_registry)

    deployer.deploy()
    deployer.assign_beneficiary(checksum_address=testerchain.unassigned_accounts[0])
    deployer.initial_deposit(value=2 * token_economics.minimum_allowed_locked,
                             duration_seconds=ONE_YEAR_IN_SECONDS)
    deployer.enroll_principal_contract()
    return allocation_registry
Exemple #6
0
def test_deploy_and_allocate(agency, token_economics, test_registry):
    token_agent, staking_agent, policy_agent = agency
    testerchain = policy_agent.blockchain
    origin = testerchain.etherbase_account

    deployments = dict()
    allocation = token_economics.minimum_allowed_locked * 1
    number_of_deployments = 1

    _last_deployment_address = None
    for index in range(number_of_deployments):
        escrow_deployer = PreallocationEscrowDeployer(deployer_address=origin,
                                                      registry=test_registry)

        _deployment_txhashes = escrow_deployer.deploy()

        # Ensure we have the correct assembly of address and abi
        assert escrow_deployer.contract.address == escrow_deployer.contract.address

        # Ensure each deployment is unique
        if _last_deployment_address:
            assert escrow_deployer.contract.address != _last_deployment_address
        _last_deployment_address = escrow_deployer.contract.address

        deployments[escrow_deployer.contract.address] = escrow_deployer
    assert len(deployments) == number_of_deployments

    # Let some time pass
    testerchain.time_travel(hours=3)
    assert token_agent.get_balance(address=origin) > 1

    # Start allocating tokens
    deposit_receipts, approve_hashes = list(), dict()
    for address, deployer in deployments.items():
        assert deployer.deployer_address == origin

        deposit_receipt = deployer.initial_deposit(
            value=allocation,
            duration_seconds=token_economics.maximum_rewarded_periods)
        deposit_receipts.append(deposit_receipt)

        beneficiary = random.choice(testerchain.unassigned_accounts)
        _assign_receipt = deployer.assign_beneficiary(beneficiary)

    assert len(deposit_receipts) == number_of_deployments == len(deployments)
Exemple #7
0
def _patch_individual_allocation_fetch_latest_publication(
        agency, test_registry):
    empty_allocation_escrow_deployer = PreallocationEscrowDeployer(
        registry=test_registry)
    allocation_contract_abi = empty_allocation_escrow_deployer.get_contract_abi(
    )
    allocation_template = {
        "BENEFICIARY_ADDRESS":
        ["ALLOCATION_CONTRACT_ADDRESS", allocation_contract_abi]
    }

    def new_fetch(*args, **kwargs):
        return json.dumps(allocation_template).encode()

    original_fetch = GithubRegistrySource.fetch_latest_publication
    GithubRegistrySource.fetch_latest_publication = new_fetch
    yield
    GithubRegistrySource.fetch_latest_publication = original_fetch
def patch_fetch_latest_publication(test_registry):
    empty_allocation_escrow_deployer = PreallocationEscrowDeployer(
        registry=test_registry)
    allocation_contract_abi = empty_allocation_escrow_deployer.get_contract_abi(
    )
    allocation_template = {
        "BENEFICIARY_ADDRESS":
        ["ALLOCATION_CONTRACT_ADDRESS", allocation_contract_abi]
    }
    new_fetch_result = json.dumps(allocation_template).encode()

    original_fetch = IndividualAllocationRegistry.fetch_latest_publication

    def new_fetch(*args, **kwargs):
        return new_fetch_result

    IndividualAllocationRegistry.fetch_latest_publication = new_fetch
    yield
    IndividualAllocationRegistry.fetch_latest_publication = original_fetch
Exemple #9
0
    def deploy_beneficiary_contracts(
        self,
        allocations: List[Dict[str, Union[str, int]]],
        allocation_outfile: str = None,
        allocation_registry: AllocationRegistry = None,
        crash_on_failure: bool = True,
        interactive: bool = True,
        emitter: StdoutEmitter = None,
    ) -> Dict[str, dict]:
        """
        The allocation file is a JSON file containing a list of allocations. Each allocation has a:
          * 'beneficiary_address': Checksum address of the beneficiary
          * 'name': User-friendly name of the beneficiary (Optional)
          * 'amount': Amount of tokens locked, in NuNits
          * 'duration_seconds': Lock duration expressed in seconds

        Example allocation file:

        [ {'beneficiary_address': '0xdeadbeef', 'name': 'H. E. Pennypacker', 'amount': 100, 'duration_seconds': 31536000},
          {'beneficiary_address': '0xabced120', 'amount': 133432, 'duration_seconds': 31536000},
          {'beneficiary_address': '0xf7aefec2', 'amount': 999, 'duration_seconds': 31536000}]

        """

        if interactive and not emitter:
            raise ValueError(
                "'emitter' is a required keyword argument when interactive is True."
            )

        if allocation_registry and allocation_outfile:
            raise self.ActorError(
                "Pass either allocation registry or allocation_outfile, not both."
            )
        if allocation_registry is None:
            allocation_registry = AllocationRegistry(
                filepath=allocation_outfile)

        if emitter:
            paint_input_allocation_file(emitter, allocations)

        if interactive:
            click.confirm("Continue with the allocation process?", abort=True)

        total_to_allocate = NU.from_nunits(
            sum(allocation['amount'] for allocation in allocations))
        balance = ContractAgency.get_agent(NucypherTokenAgent,
                                           self.registry).get_balance(
                                               self.deployer_address)
        if balance < total_to_allocate:
            raise ValueError(
                f"Not enough tokens to allocate. We need at least {total_to_allocate}."
            )

        allocation_receipts, failed, allocated = dict(), list(), list()
        total_deployment_transactions = len(allocations) * 4

        # Create an allocation template file, containing the allocation contract ABI and placeholder values
        # for the beneficiary and contract addresses. This file will be shared with all allocation users.
        empty_allocation_escrow_deployer = PreallocationEscrowDeployer(
            registry=self.registry)
        allocation_contract_abi = empty_allocation_escrow_deployer.get_contract_abi(
        )
        allocation_template = {
            "BENEFICIARY_ADDRESS":
            ["ALLOCATION_CONTRACT_ADDRESS", allocation_contract_abi]
        }

        parent_path = Path(allocation_registry.filepath
                           ).parent  # Use same folder as allocation registry
        template_filename = IndividualAllocationRegistry.REGISTRY_NAME
        template_filepath = os.path.join(parent_path, template_filename)
        AllocationRegistry(filepath=template_filepath).write(
            registry_data=allocation_template)
        if emitter:
            emitter.echo(
                f"Saved allocation template file to {template_filepath}",
                color='blue',
                bold=True)

        # Deploy each allocation contract
        with click.progressbar(length=total_deployment_transactions,
                               label="Allocation progress",
                               show_eta=False) as bar:
            bar.short_limit = 0
            for allocation in allocations:

                # TODO: Check if allocation already exists in allocation registry

                beneficiary = allocation['beneficiary_address']
                name = allocation.get('name', 'No name provided')

                if interactive:
                    click.pause(
                        info=f"\nPress any key to continue with allocation for "
                        f"beneficiary {beneficiary} ({name})")

                if emitter:
                    emitter.echo(
                        f"\nDeploying PreallocationEscrow contract for beneficiary {beneficiary} ({name})..."
                    )
                    bar._last_line = None
                    bar.render_progress()

                deployer = self.deploy_preallocation_escrow(
                    allocation_registry=allocation_registry, progress=bar)

                amount = allocation['amount']
                duration = allocation['duration_seconds']
                try:
                    receipts = deployer.deliver(
                        value=amount,
                        duration=duration,
                        beneficiary_address=beneficiary,
                        progress=bar)
                except TransactionFailed as e:
                    if crash_on_failure:
                        raise
                    self.log.debug(
                        f"Failed allocation transaction for {NU.from_nunits(amount)} to {beneficiary}: {e}"
                    )
                    failed.append(allocation)
                    continue

                else:
                    allocation_receipts[beneficiary] = receipts
                    allocation_contract_address = deployer.contract_address
                    self.log.info(
                        f"Created {deployer.contract_name} contract at {allocation_contract_address} "
                        f"for beneficiary {beneficiary}.")
                    allocated.append((allocation, allocation_contract_address))

                    # Create individual allocation file
                    individual_allocation_filename = f'allocation-{beneficiary}.json'
                    individual_allocation_filepath = os.path.join(
                        parent_path, individual_allocation_filename)
                    individual_allocation_file_data = {
                        'beneficiary_address': beneficiary,
                        'contract_address': allocation_contract_address
                    }
                    with open(individual_allocation_filepath, 'w') as outfile:
                        json.dump(individual_allocation_file_data, outfile)

                    if emitter:
                        blockchain = BlockchainInterfaceFactory.get_interface()
                        paint_contract_deployment(
                            contract_name=deployer.contract_name,
                            receipts=receipts,
                            contract_address=deployer.contract_address,
                            emitter=emitter,
                            chain_name=blockchain.client.chain_name,
                            open_in_browser=False)
                        emitter.echo(
                            f"Saved individual allocation file to {individual_allocation_filepath}",
                            color='blue',
                            bold=True)

            if emitter:
                paint_deployed_allocations(emitter, allocated, failed)

            csv_filename = f'allocations-{self.deployer_address[:6]}-{maya.now().epoch}.csv'
            csv_filepath = os.path.join(parent_path, csv_filename)
            write_deployed_allocations_to_csv(csv_filepath, allocated, failed)
            if emitter:
                emitter.echo(f"Saved allocation summary CSV to {csv_filepath}",
                             color='blue',
                             bold=True)

            if failed:
                # TODO: More with these failures: send to isolated logfile, and reattempt
                self.log.critical(
                    f"FAILED TOKEN ALLOCATION - {len(failed)} allocations failed."
                )

        return allocation_receipts