Пример #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()
Пример #2
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
Пример #4
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