Esempio n. 1
0
    def test_create_project_happy_case(self,
                                       github_organization_mock: MagicMock,
                                       create_repo_mock: MagicMock,
                                       get_w3_mock: MagicMock,
                                       transaction_mock: MagicMock,
                                       redis_lock_mock: MagicMock):
        Project.create_mycro_dao(constants.MYCRO_ADDRESS,
                                 constants.MYCRO_PROJECT_SYMBOL,
                                 constants.DECIMALS)
        project = Project.objects.create(symbol=constants.PROJECT_SYMBOL,
                                         repo_name=constants.PROJECT_NAME,
                                         decimals=constants.DECIMALS,
                                         initial_balances=constants.CREATORS_BALANCES)

        # TODO make this more of an integration test by using constants.W3 like the create_asc tests
        w3 = get_w3_mock.return_value
        w3.eth.waitForTransactionReceipt.return_value = {
            'contractAddress'  : constants.PROJECT_ADDRESS,
            'cumulativeGasUsed': 2,
            'gasUsed'          : 1,
            'blockNumber'      : 3,
            'status'           : 4}
        w3.eth.getBalance.return_value = int(10e18)

        tasks.create_project(project.pk)

        # two transactions, one for deploying and once for registering
        transaction_mock.objects.create.assert_any_call(
            wallet=self.wallet,
            hash=get_w3_mock.return_value.eth.sendRawTransaction.return_value.hex.return_value,
            value=ANY,
            chain_id=ANY,
            nonce=ANY,
            gas_limit=ANY,
            gas_price=ANY,
            data=ANY,
            to=ANY,
            contract_address=constants.PROJECT_ADDRESS,
            cumulative_gas_used=2,
            gas_used=1,
            block_number=3,
            status=4
        )

        # called twice for deployment and twice for registrations
        self.assertEqual(4,
                         get_w3_mock.return_value.eth.waitForTransactionReceipt.call_count)
        self.assertEqual(4, w3.eth.sendRawTransaction.call_count)

        create_repo_mock.assert_called_once_with(
            repo_name=constants.PROJECT_NAME,
            organization=github_organization_mock.return_value)

        project.refresh_from_db()
        self.assertEqual(constants.PROJECT_ADDRESS, project.dao_address)
        self.assertEqual(BlockchainState.COMPLETED, project.blockchain_state)
        self.assertNotEqual('', project.merge_module_address)

        redis_lock_mock.assert_called_once_with(tasks.REDIS_CREATE_CONTRACT_LOCK)
Esempio n. 2
0
    def mutate(self, info, project_name: str, creator_address: str):
        CreateProject._validate_project_name(
            proposed_project_name=project_name)
        mycro_project = Project.get_mycro_dao()
        if mycro_project is None:
            raise ProjectException(
                "Could not find mycro dao. Cannot create new project.")

        if not Web3.isAddress(creator_address):
            raise ProjectException('Supplied address is not valid')

        total_supply = 1000
        symbol = project_name[:3]
        decimals = 18
        initial_balances = {creator_address: total_supply}

        # create a row in the a db and a repository in github
        project = Project.objects.create(
            repo_name=project_name,
            last_merge_event_block=0,
            is_mycro_dao=False,
            symbol=symbol,
            decimals=decimals,
            blockchain_state=BlockchainState.PENDING.value,
            initial_balances=initial_balances)

        create_project.delay(project.id)

        return CreateProject(project=project)
Esempio n. 3
0
def create_project(self, project_id: int) -> None:
    # TODO add mechanism to retry if anything in here fails
    # TODO there's lots of opportunity for failure in this function, we should be
    # more resilient

    logger.info(f'Attempting to get lock to create project {project_id}')

    # TODO extend to support locking based on wallets
    with REDIS_CLIENT.lock('create-project'):
        logger.info(f'Acquired lock to create project {project_id}')
        project = Project.objects.get(pk=project_id)

        project.blockchain_state = BlockchainState.STARTED.value
        project.save()

        compiler = ContractCompiler()
        mycro_project = Project.get_mycro_dao()

        w3 = deploy.get_w3()

        contract_interface = compiler.get_contract_interface('mycro.sol',
                                                             'MycroCoin')
        mycro_contract = w3.eth.contract(abi=contract_interface['abi'],
                                         address=mycro_project.dao_address)

        base_dao_interface = compiler.get_contract_interface('base_dao.sol',
                                                             'BaseDao')
        merge_module_interface = compiler.get_contract_interface(
            'merge_module.sol', 'MergeModule')

        creators = []
        creator_balances = []
        logger.info(f'Project balances are {project.initial_balances}')
        for creator, balance in project.initial_balances.items():
            creators.append(creator)
            creator_balances.append(balance)

        total_supply = sum(creator_balances)

        # TODO add validation of project properties
        w3, dao_contract, dao_address, _ = deploy.deploy(base_dao_interface,
                                                         project.symbol,
                                                         project.repo_name,
                                                         project.decimals,
                                                         total_supply,
                                                         creators,
                                                         creator_balances,
                                                         private_key=Wallet.objects.first().private_key)

        _, _, merge_module_address, _ = deploy.deploy(merge_module_interface,
                                                      private_key=Wallet.objects.first().private_key)

        deploy.call_contract_function(
            dao_contract.functions.registerModule,
            merge_module_address,
            private_key=Wallet.objects.first().private_key)
        deploy.call_contract_function(
            mycro_contract.functions.registerProject,
            dao_address,
            private_key=Wallet.objects.first().private_key)


        project.blockchain_state = BlockchainState.COMPLETED.value
        project.dao_address = dao_address
        project.merge_module_address = merge_module_address
        project.save()

        github.create_repo(repo_name=project.repo_name,
                           organization=settings.github_organization())

    logger.info(f'Finished creating project {project_id}')
Esempio n. 4
0
    # if the wallet isn't funded, fund it
    main_wallet = Wallet.objects.first()
    deploy.fund_account_if_needed(w3, settings.ethereum_private_key(),
                                  main_wallet.private_key)

    # TODO remove this when we no longer need to deploy the mycro contract on init
    # maybe we should hide this behind an env variable because this is useful for testing
    mycro_project = Project.objects.filter(is_mycro_dao=True)
    if len(mycro_project) == 0:
        compiler = ContractCompiler()
        _, mycro_contract, mycro_address, mycro_instance = deploy.deploy(
            compiler.get_contract_interface('mycro.sol', 'MycroCoin'),
            private_key=main_wallet.private_key,
            timeout=None)
        Project.create_mycro_dao(mycro_address,
                                 symbol=mycro_instance.symbol(),
                                 decimals=mycro_instance.decimals())
    elif len(mycro_project) > 1:
        raise ValueError("Shit there are two mycro DAOs")

    # Set up background tasks which monitor blockchain for events
    schedule, created = IntervalSchedule.objects.get_or_create(
        every=5,
        period=IntervalSchedule.SECONDS,
    )
    if not PeriodicTask.objects.filter(name=MERGE_PR_BEAT_NAME):
        PeriodicTask.objects.create(interval=schedule,
                                    name=MERGE_PR_BEAT_NAME,
                                    task='backend.server.tasks.process_merges')