예제 #1
0
    def test_safe_creation_with_fixed_cost(self):
        s = generate_valid_s()
        owner1, _ = get_eth_address_with_key()
        owner2, _ = get_eth_address_with_key()
        serializer = SafeCreationSerializer(data={
            's': s,
            'owners': [owner1, owner2],
            'threshold': 2
        })
        self.assertTrue(serializer.is_valid())
        fixed_creation_cost = 123
        with self.settings(SAFE_FIXED_CREATION_COST=fixed_creation_cost):
            SafeCreationServiceProvider.del_singleton()
            response = self.client.post(reverse('v1:safe-creation'),
                                        data=serializer.data,
                                        format='json')
            response_json = response.json()
            self.assertEqual(response.status_code, status.HTTP_201_CREATED)
            deployer = response_json['deployer']
            self.assertTrue(check_checksum(deployer))
            self.assertTrue(check_checksum(response_json['safe']))
            self.assertTrue(check_checksum(response_json['funder']))
            self.assertEqual(response_json['paymentToken'], NULL_ADDRESS)
            self.assertEqual(int(response_json['payment']),
                             fixed_creation_cost)

            safe_creation = SafeCreation.objects.get(deployer=deployer)
            self.assertEqual(safe_creation.payment_token, None)
            self.assertEqual(safe_creation.payment, fixed_creation_cost)
            self.assertGreater(safe_creation.wei_deploy_cost(),
                               safe_creation.payment)
            SafeCreationServiceProvider.del_singleton()
예제 #2
0
    def test_safe_creation_with_fixed_cost(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        data = {
            "saltNonce": salt_nonce,
            "owners": owners,
            "threshold": len(owners)
        }

        fixed_creation_cost = 456
        with self.settings(SAFE_FIXED_CREATION_COST=fixed_creation_cost):
            SafeCreationServiceProvider.del_singleton()
            response = self.client.post(reverse("v3:safe-creation"),
                                        data,
                                        format="json")
            SafeCreationServiceProvider.del_singleton()

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        safe_address = response_json["safe"]
        self.assertTrue(check_checksum(safe_address))
        self.assertTrue(check_checksum(response_json["paymentReceiver"]))
        self.assertEqual(response_json["paymentToken"], NULL_ADDRESS)
        self.assertEqual(response_json["payment"], str(fixed_creation_cost))
        self.assertGreater(int(response_json["gasEstimated"]), 0)
        self.assertGreater(int(response_json["gasPriceEstimated"]), 0)
        self.assertGreater(len(response_json["setupData"]), 2)
예제 #3
0
    def test_safe_creation_with_fixed_cost(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        data = {
            'saltNonce': salt_nonce,
            'owners': owners,
            'threshold': len(owners)
        }

        fixed_creation_cost = 123
        with self.settings(SAFE_FIXED_CREATION_COST=fixed_creation_cost):
            SafeCreationServiceProvider.del_singleton()
            response = self.client.post(reverse('v2:safe-creation'), data, format='json')
            SafeCreationServiceProvider.del_singleton()

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        safe_address = response_json['safe']
        self.assertTrue(check_checksum(safe_address))
        self.assertTrue(check_checksum(response_json['paymentReceiver']))
        self.assertEqual(response_json['paymentToken'], NULL_ADDRESS)
        self.assertEqual(response_json['payment'], '123')
        self.assertGreater(int(response_json['gasEstimated']), 0)
        self.assertGreater(int(response_json['gasPriceEstimated']), 0)
        self.assertGreater(len(response_json['setupData']), 2)
예제 #4
0
    def test_safe_creation_with_payment_token(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        payment_token = Account.create().address
        data = {
            "saltNonce": salt_nonce,
            "owners": owners,
            "threshold": len(owners),
            "paymentToken": payment_token,
        }

        response = self.client.post(reverse("v3:safe-creation"),
                                    data=data,
                                    format="json")
        self.assertEqual(response.status_code,
                         status.HTTP_422_UNPROCESSABLE_ENTITY)
        response_json = response.json()
        self.assertIn("InvalidPaymentToken", response_json["exception"])
        self.assertIn(payment_token, response_json["exception"])

        fixed_eth_conversion = 0.1
        token_model = TokenFactory(address=payment_token,
                                   fixed_eth_conversion=fixed_eth_conversion)
        response = self.client.post(reverse("v3:safe-creation"),
                                    data,
                                    format="json")
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        safe_address = response_json["safe"]
        self.assertTrue(check_checksum(safe_address))
        self.assertTrue(check_checksum(response_json["paymentReceiver"]))
        self.assertEqual(response_json["paymentToken"], payment_token)
        self.assertEqual(
            int(response_json["payment"]),
            int(response_json["gasEstimated"]) *
            int(response_json["gasPriceEstimated"]) *
            (1 / fixed_eth_conversion),
        )
        self.assertGreater(int(response_json["gasEstimated"]), 0)
        self.assertGreater(int(response_json["gasPriceEstimated"]), 0)
        self.assertGreater(len(response_json["setupData"]), 2)

        self.assertTrue(SafeContract.objects.filter(address=safe_address))
        self.assertTrue(
            SafeCreation2.objects.filter(owners__contains=[owners[0]]))
        safe_creation = SafeCreation2.objects.get(safe=safe_address)
        self.assertEqual(safe_creation.payment_token, payment_token)
        # Payment includes deployment gas + gas to send eth to the deployer
        self.assertEqual(
            safe_creation.payment,
            safe_creation.wei_estimated_deploy_cost() *
            (1 / fixed_eth_conversion),
        )
예제 #5
0
def api(coin, address):
    if coin == 'bitcoin':
        if not address:
            return "Please enter an address"

        valid = validate_btc(address)

        if valid:
            return jsonify({'blockchain': coin, 'valid_address': True})
        if not valid:
            return jsonify({'blockchain': coin, 'valid_address': False})

    if coin == 'ethereum':
        if not address:
            return "Please enter an address"
        try:
            check_checksum(address)
            valid = True
        except:
            valid = False

        return jsonify({'blockchain': coin, 'valid_address': valid})

    if coin == 'ripple':
        if not address:
            return "Please enter an address"

        valid = validate_ripple_address(address)

        if valid:
            return jsonify({'blockchain': coin, 'valid_address': True})
        if not valid:
            return jsonify({'blockchain': coin, 'valid_address': False})

        return 'ripple'

    if coin == 'monero':
        if not address:
            return "Please enter an address"

        valid = validate_monero_address(address)

        if valid:
            return jsonify({'blockchain': coin, 'valid_address': True})
        if not valid:
            return jsonify({'blockchain': coin, 'valid_address': False})

        return 'ripple'
        return 'monero'

    return 'NO REQUEST MADE'
예제 #6
0
    def test_ethereum_address_field(self):
        address, _ = get_eth_address_with_key()
        self.assertTrue(check_checksum(address))
        ethereum_address = EthereumAddress.objects.create(value=address)
        ethereum_address.refresh_from_db()
        self.assertTrue(check_checksum(ethereum_address.value))
        self.assertEqual(address, ethereum_address.value)

        ethereum_address = EthereumAddress.objects.create(value=None)
        ethereum_address.refresh_from_db()
        self.assertIsNone(ethereum_address.value)

        with self.assertRaises(Exception):
            EthereumAddress.objects.create(value='0x23')
    def test_safe_creation(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        data = {
            'saltNonce': salt_nonce,
            'owners': owners,
            'threshold': len(owners)
        }
        response = self.client.post(reverse('v3:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        safe_address = response_json['safe']
        self.assertTrue(check_checksum(safe_address))
        self.assertTrue(check_checksum(response_json['paymentReceiver']))
        self.assertEqual(response_json['paymentToken'], NULL_ADDRESS)
        self.assertEqual(int(response_json['payment']),
                         int(response_json['gasEstimated']) * int(response_json['gasPriceEstimated']))
        self.assertGreater(int(response_json['gasEstimated']), 0)
        self.assertGreater(int(response_json['gasPriceEstimated']), 0)
        self.assertGreater(len(response_json['setupData']), 2)
        self.assertEqual(response_json['masterCopy'], settings.SAFE_CONTRACT_ADDRESS)

        self.assertTrue(SafeContract.objects.filter(address=safe_address))
        self.assertTrue(SafeCreation2.objects.filter(owners__contains=[owners[0]]))
        safe_creation = SafeCreation2.objects.get(safe=safe_address)
        self.assertEqual(safe_creation.payment_token, None)
        # Payment includes deployment gas + gas to send eth to the deployer
        self.assertEqual(safe_creation.payment, safe_creation.wei_estimated_deploy_cost())

        # Deploy the Safe to check it
        self.send_ether(safe_address, int(response_json['payment']))
        safe_creation2 = SafeCreationServiceProvider().deploy_create2_safe_tx(safe_address)
        self.ethereum_client.get_transaction_receipt(safe_creation2.tx_hash, timeout=20)
        safe = Safe(safe_address, self.ethereum_client)
        self.assertEqual(safe.retrieve_master_copy_address(), response_json['masterCopy'])
        self.assertEqual(safe.retrieve_owners(), owners)

        # Test exception when same Safe is created
        response = self.client.post(reverse('v3:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_422_UNPROCESSABLE_ENTITY)
        self.assertIn('SafeAlreadyExistsException', response.json()['exception'])

        data = {
            'salt_nonce': -1,
            'owners': owners,
            'threshold': 2
        }
        response = self.client.post(reverse('v3:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_422_UNPROCESSABLE_ENTITY)
예제 #8
0
    def validate(self, data):
        super().validate(data)

        if not data['to'] and not data['data']:
            raise ValidationError('`data` and `to` cannot both be null')
        if 'to' in data and not check_checksum(data['to']):
            raise ValidationError('`to` must be a valid checksumed address')

        if data['operation'] == 2:
            if data['to']:
                raise ValidationError(
                    'Operation is Create, but `to` was provided')
        elif not data['to']:
            raise ValidationError(
                'Operation is not create, but `to` was not provided')

        safe_service = SafeServiceProvider()
        contract_transaction_hash = safe_service.get_hash_for_safe_tx(
            data['safe'], data['to'], data['value'], data['data'],
            data['operation'], data['nonce'])

        if contract_transaction_hash != data['contract_transaction_hash']:
            raise ValidationError('contract_transaction_hash is not valid')

        return data
예제 #9
0
def deploy_create2_safe_task(self,
                             safe_address: str,
                             retry: bool = True) -> None:
    """
    Check if user has sent enough ether or tokens to the safe account
    If every condition is met safe is deployed
    :param safe_address: safe account
    :param retry: if True, retries are allowed, otherwise don't retry
    """

    assert check_checksum(safe_address)

    redis = RedisRepository().redis
    lock_name = f'locks:deploy_create2_safe:{safe_address}'
    try:
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            try:
                SafeCreationServiceProvider().deploy_create2_safe_tx(
                    safe_address)
            except NotEnoughFundingForCreation:
                if retry:
                    raise self.retry(countdown=30)
    except LockError:
        logger.warning('Cannot get lock={} for deploying safe={}'.format(
            lock_name, safe_address))
    def test_ethereum_signed_message(self):
        eth_address, eth_key = get_eth_address_with_key()
        eth_address_bad_checksum = eth_address.lower()

        prefix = settings.ETH_HASH_PREFIX
        message = faker.name()
        prefixed_message = prefix + message
        message_hash = utils.sha3(prefixed_message)
        v, r, s = utils.ecsign(message_hash, eth_key)
        ethereum_signed_message = EthereumSignedMessage(message, v, r, s)

        self.assertTrue(ethereum_signed_message.check_message_hash(message))

        self.assertTrue(
            ethereum_signed_message.check_signing_address(eth_address))
        self.assertTrue(
            ethereum_signed_message.check_signing_address(eth_address.lower()))
        self.assertTrue(
            ethereum_signed_message.check_signing_address(eth_address[2:]))
        self.assertTrue(
            ethereum_signed_message.check_signing_address(
                eth_address_bad_checksum))

        self.assertEqual(ethereum_signed_message.get_signing_address(),
                         eth_address)
        self.assertTrue(
            utils.check_checksum(
                ethereum_signed_message.get_signing_address()))
예제 #11
0
 def pack_address(self, token_address: str) -> str:
     """
     Prepares Circles token address
     :param token_address:
     :return: packed string
     """
     assert check_checksum(token_address)
     return MAPPING_NULL_PREFIX + token_address[2:]
예제 #12
0
def circles_onboarding_organization_safe_task(safe_address: str,
                                              owner_address: str) -> None:
    """
    Check if create2 Safe is being created by a trusted user
    :param safe_address: Address of the safe to-be-created
    :param owner_address: Address of the first safe owner
    """

    assert check_checksum(safe_address)
    assert check_checksum(owner_address)

    try:
        redis = RedisRepository().redis
        lock_name = f'locks:circles_onboarding_organization_safe_task:{safe_address}'
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            logger.info('Check deploying Safe for organization .. {}'.format(
                safe_address))
            try:
                SafeCreationServiceProvider().deploy_create2_safe_tx(
                    safe_address)
            except SafeCreation2.DoesNotExist:
                pass
            except NotEnoughFundingForCreation:
                logger.info('Safe does not have enough fund for deployment, '
                            'check owner {}'.format(owner_address))
                # If we have enough trust connections, fund safe
                if GraphQLService().check_trust_connections_by_user(
                        owner_address):
                    logger.info(
                        'Fund Safe deployment for {}'.format(safe_address))
                    safe_creation = SafeCreation2.objects.get(
                        safe=safe_address)
                    safe_deploy_cost = safe_creation.wei_estimated_deploy_cost(
                    )
                    FundingServiceProvider().send_eth_to(safe_address,
                                                         safe_deploy_cost,
                                                         gas=24000)
                else:
                    logger.info(
                        'Owner {} does not have a deployed safe'.format(
                            owner_address))
    except LockError:
        pass
예제 #13
0
    def test_safe_creation(self):
        s = generate_valid_s()
        owner1, _ = get_eth_address_with_key()
        owner2, _ = get_eth_address_with_key()
        serializer = SafeCreationSerializer(data={
            's': s,
            'owners': [owner1, owner2],
            'threshold': 2
        })
        self.assertTrue(serializer.is_valid())
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        response_json = response.json()
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        deployer = response_json['deployer']
        self.assertTrue(check_checksum(deployer))
        self.assertTrue(check_checksum(response_json['safe']))
        self.assertTrue(check_checksum(response_json['funder']))
        self.assertEqual(response_json['paymentToken'], NULL_ADDRESS)
        self.assertGreater(int(response_json['payment']), 0)

        self.assertTrue(
            SafeContract.objects.filter(address=response.data['safe']))
        self.assertTrue(SafeCreation.objects.filter(owners__contains=[owner1]))
        safe_creation = SafeCreation.objects.get(deployer=deployer)
        self.assertEqual(safe_creation.payment_token, None)
        # Payment includes deployment gas + gas to send eth to the deployer
        self.assertGreater(safe_creation.payment,
                           safe_creation.wei_deploy_cost())

        serializer = SafeCreationSerializer(data={
            's': -1,
            'owners': [owner1, owner2],
            'threshold': 2
        })
        self.assertFalse(serializer.is_valid())
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code,
                         status.HTTP_422_UNPROCESSABLE_ENTITY)
예제 #14
0
def circles_onboarding_organization_signup_task(safe_address: str) -> None:
    """
    Check if Organization Safe is already registered in the Hub, if not, fund it
    :param safe_address: Address of the created safe
    """

    assert check_checksum(safe_address)

    # Additional funds for organization deployments (it should at least cover
    # one `trust` method call) next to the `organizationSignup` method
    ADDITIONAL_START_FUNDS = 100000000000000

    try:
        redis = RedisRepository().redis
        lock_name = f'locks:circles_onboarding_organization_signup_task:{safe_address}'
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            logger.info(
                'Fund organizationSignup task for {}'.format(safe_address))

            ethereum_client = EthereumClientProvider()

            # Do nothing if account already exists in Hub
            if CirclesService(ethereum_client).is_organization_deployed(
                    safe_address):
                logger.info('Organization is already deployed for {}'.format(
                    safe_address))
                return

            # Do nothing if the signup is already funded
            transaction_service = TransactionServiceProvider()

            # Sum `organizationSignup` and additional `trust` transactions
            # costs as the organization needs to trust at least one user in the
            # beginning to receive more funds
            payment = transaction_service.estimate_circles_organization_signup_tx(
                safe_address) + ADDITIONAL_START_FUNDS
            safe_balance = ethereum_client.get_balance(safe_address)
            logger.info(
                'Found %d balance for organization deployment of safe=%s. Required=%d',
                safe_balance, safe_address, payment)
            if safe_balance >= payment:
                logger.info(
                    'Organization is already funded {}'.format(safe_address))
                return

            # Otherwise fund deployment
            logger.info('Fund Organization {}'.format(safe_address))
            FundingServiceProvider().send_eth_to(safe_address,
                                                 payment - safe_balance,
                                                 gas=30000,
                                                 retry=True)
    except LockError:
        pass
예제 #15
0
def validate_checksumed_address(address):
    try:
        if not check_checksum(address):
            raise ValidationError(
                '%(address)s has an invalid checksum',
                params={'address': address},
            )
    except:
        raise ValidationError(
            '%(address)s is not a valid ethereum address',
            params={'address': address},
        )
예제 #16
0
def findLowerCase(addressList):
    total = len(addressList)
    lower = 0
    valid = 0
    validList = []
    for address in addressList:
        if address == address.lower():
            lower = lower + 1
            if check_checksum(address):
                valid = valid + 1
                validList.append(address + '\n')
    return validList, total, lower, valid
예제 #17
0
    def test_safe_creation(self):
        salt_nonce = generate_salt_nonce()
        owners = [Account.create().address for _ in range(2)]
        data = {
            'saltNonce': salt_nonce,
            'owners': owners,
            'threshold': len(owners)
        }
        response = self.client.post(reverse('v2:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        safe_address = response_json['safe']
        self.assertTrue(check_checksum(safe_address))
        self.assertTrue(check_checksum(response_json['paymentReceiver']))
        self.assertEqual(response_json['paymentToken'], NULL_ADDRESS)
        self.assertEqual(int(response_json['payment']),
                         int(response_json['gasEstimated']) * int(response_json['gasPriceEstimated']))
        self.assertGreater(int(response_json['gasEstimated']), 0)
        self.assertGreater(int(response_json['gasPriceEstimated']), 0)
        self.assertGreater(len(response_json['setupData']), 2)

        self.assertTrue(SafeContract.objects.filter(address=safe_address))
        self.assertTrue(SafeCreation2.objects.filter(owners__contains=[owners[0]]))
        safe_creation = SafeCreation2.objects.get(safe=safe_address)
        self.assertEqual(safe_creation.payment_token, None)
        # Payment includes deployment gas + gas to send eth to the deployer
        self.assertEqual(safe_creation.payment, safe_creation.wei_estimated_deploy_cost())

        # Test exception when same Safe is created
        response = self.client.post(reverse('v2:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_422_UNPROCESSABLE_ENTITY)
        self.assertIn('SafeAlreadyExistsException', response.json()['exception'])

        data = {
            'salt_nonce': -1,
            'owners': owners,
            'threshold': 2
        }
        response = self.client.post(reverse('v2:safe-creation'), data, format='json')
        self.assertEqual(response.status_code, status.HTTP_422_UNPROCESSABLE_ENTITY)
    def send_eth_to(self,
                    to: str,
                    gas_price: int,
                    value: int,
                    gas: int = 22000) -> bytes:
        """
        Send ether using configured account
        :param to: to
        :param gas_price: gas_price
        :param value: value(wei)
        :param gas: gas, defaults to 22000
        :return: tx_hash
        """

        assert check_checksum(to)

        assert value < self.w3.toWei(self.max_eth_to_send, 'ether')

        private_key = self.funder_private_key

        if private_key:
            ethereum_account = self.private_key_to_address(private_key)
            tx = {
                'to': to,
                'value': value,
                'gas': gas,
                'gasPrice': gas_price,
                'nonce': self.get_nonce_for_account(ethereum_account),
            }

            signed_tx = self.w3.eth.account.signTransaction(
                tx, private_key=private_key)
            logger.debug('Sending %d wei from %s to %s', value,
                         ethereum_account, to)
            return self.w3.eth.sendRawTransaction(signed_tx.rawTransaction)
        elif self.w3.eth.accounts:
            ethereum_account = self.w3.eth.accounts[0]
            tx = {
                'from': ethereum_account,
                'to': to,
                'value': value,
                'gas': gas,
                'gasPrice': gas_price,
                'nonce': self.get_nonce_for_account(ethereum_account),
            }
            logger.debug('Sending %d wei from %s to %s', value,
                         ethereum_account, to)
            return self.w3.eth.sendTransaction(tx)
        else:
            logger.error('No ethereum account configured')
            raise ValueError(
                "Ethereum account was not configured or unlocked in the node")
예제 #19
0
def begin_circles_onboarding_organization_task(self, safe_address: str,
                                               owner_address: str) -> None:
    """
    Starts a multi-step onboarding task for Circles organizations which 1. funds
    deploys a Gnosis Safe for them 2. funds the deployment of their Organization.
    :param safe_address: Address of the safe to-be-created
    :param owner_address: Address of the first safe owner
    """

    assert check_checksum(safe_address)
    assert check_checksum(owner_address)

    redis = RedisRepository().redis
    lock_name = f'locks:begin_circles_onboarding_organization_task:{safe_address}'
    try:
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            logger.info(
                'Start onboarding for Circles Organization Safe {}'.format(
                    safe_address))
            # Deploy Safe when it does not exist yet
            safe_creation2 = SafeCreation2.objects.get(safe=safe_address)
            if not safe_creation2.tx_hash:
                logger.info(
                    'Safe does not exist yet, start deploying it {}'.format(
                        safe_address))
                circles_onboarding_organization_safe_task.delay(
                    safe_address, owner_address)
                # Retry later to check for signup funding
                raise self.retry(countdown=30)
            else:
                logger.info(
                    'Safe exists, start funding organizationSignup for {}'.
                    format(safe_address))
                # Fund deployment when Organization does not exist yet
                circles_onboarding_organization_signup_task.delay(safe_address)
    except LockError:
        pass
예제 #20
0
    def send_eth_to(self,
                    private_key: str,
                    to: str,
                    gas_price: int,
                    value: int,
                    gas: int = 22000,
                    nonce: Optional[int] = None,
                    retry: bool = False,
                    block_identifier: Optional[str] = 'pending') -> bytes:
        """
        Send ether using configured account
        :param to: to
        :param gas_price: gas_price
        :param value: value(wei)
        :param gas: gas, defaults to 22000
        :param retry: Retry if a problem is found
        :param nonce: Nonce of sender account
        :param block_identifier: Block identifier for nonce calculation
        :return: tx_hash
        """

        assert check_checksum(to)

        tx = {
            'to': to,
            'value': value,
            'gas': gas,
            'gasPrice': gas_price,
        }

        if nonce is not None:
            tx['nonce'] = nonce

        return self.send_unsigned_transaction(
            tx,
            private_key=private_key,
            retry=retry,
            block_identifier=block_identifier)
예제 #21
0
def begin_circles_onboarding_task(self, safe_address: str) -> None:
    """
    Starts a multi-step onboarding task for Circles users which 1. funds
    deploys a Gnosis Safe for them 2. funds the deployment of their Token.
    :param safe_address: Address of the safe to-be-created
    """

    assert check_checksum(safe_address)

    redis = RedisRepository().redis
    lock_name = f'locks:begin_circles_onboarding_task:{safe_address}'
    try:
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            ethereum_client = EthereumClientProvider()

            # Do nothing if Token is already deployed
            if CirclesService(ethereum_client).is_token_deployed(safe_address):
                logger.info(
                    'Token is already deployed for {}'.format(safe_address))
                return

            logger.info(
                'No token found, start onboarding for Circles Safe {}'.format(
                    safe_address))
            # Deploy Safe when it does not exist yet
            safe_creation2 = SafeCreation2.objects.get(safe=safe_address)
            if not safe_creation2.tx_hash:
                logger.info(
                    'Safe does not exist yet, start deploying it {}'.format(
                        safe_address))
                circles_onboarding_safe_task.delay(safe_address)
            else:
                logger.info('Safe exists, we are done with safe {}'.format(
                    safe_address))
    except LockError:
        pass
예제 #22
0
def main():
    '''
    Main method. Runs the program if it is used standalone (rather than as an exported library).
    '''

    parser = _get_args()

    if len(parser.target_address) != 42:
        log.error(
            "Target Address length does not appear to match the correct length of an Ethereum address"
        )
        sys.exit(1)
    if len(parser.from_address) != 42:
        log.error(
            "From Address length does not appear to match the correct length of an Ethereum address"
        )
        sys.exit(1)
    if parser.target_address[0:2] != "0x":
        log.error(
            "Target address not in expected format, expected address to start with 0x"
        )
        sys.exit(1)
    if parser.from_address[0:2] != "0x":
        log.error(
            "From address not in expected format, expected address to start with 0x"
        )
        sys.exit(1)

    if not check_checksum(parser.target_address):
        log.error(
            "Target address is not correctly encoded using EIP-55 {}".format(
                parser.target_address))
        sys.exit(1)
    if not check_checksum(parser.from_address):
        log.error(
            "From address is not correctly encoded using EIP-55 {}".format(
                parser.from_address))
        sys.exit(1)

    toAddress = normalize_address(parser.target_address)
    fromAddress = normalize_address(parser.from_address)
    gasPrice = parser.gas_price
    gasLimit = parser.gas_limit
    sendAmount = parser.amount
    if (parser.dapp_data):
        dappData = rec_bin(parser.dapp_data)
    else:
        dappData = b""

    tx, addressB, commit, randw = _generateAddressBInternal(
        fromAddress, toAddress, sendAmount, dappData, gasPrice, gasLimit)

    # print("-"* 35)
    # printRemix(fromAddress, tx, encode_hex(randw))
    print("-" * 35)

    print("AddressB: {}".format(addressB)
          )  # addressB also can retrieved using tx.to_dict().get("sender")
    print("commit: {}".format(encode_hex(commit)))
    print("witness (w): {}".format(encode_hex(randw)))
    # print("Reveal Transation (json): {}".format(tx.to_dict()))
    print("Reveal Transaction (hex): {}".format(encode_hex(rlp.encode(tx))))
    print(
        "You can use the reveal transaction hex to broadcast with any service you like, e.g.: https://ropsten.etherscan.io/pushTx"
    )
예제 #23
0
startIndex = 17
endIndex = 27

LETTERS = 22
TESTS = 10000
MAX = (endIndex - startIndex) * LETTERS

replacingSequence = list(range(0, MAX))
random.shuffle(replacingSequence)

total_found = 0
total_tested = 0
for _ in range(0, TESTS):
    originalAccount = w3.eth.account.create(secrets.token_hex(32))
    originalAddress = originalAccount.address
    if not check_checksum(originalAddress):
        print("Invalid EIP55 address")
    else:
        total_tested += 1
        found = False
        k = 0
        replacedAddress = ""
        while not found and k < MAX:

            position = startIndex + replacingSequence[k] // LETTERS
            replacedLetter = letterList[replacingSequence[k] % LETTERS]
            originalLetter = originalAddress[position]
            if replacedLetter.lower() != originalLetter.lower():
                temp = list(originalAddress)
                temp[position] = replacedLetter
                replacedAddress = "".join(temp)
예제 #24
0
def fund_deployer_task(self, safe_address: str, retry: bool = True) -> None:
    """
    Check if user has sent enough ether or tokens to the safe account
    If every condition is met ether is sent to the deployer address and `check_deployer_funded_task`
    is called to check that that tx is mined
    If everything goes well in SafeFunding `safe_funded=True` and `deployer_funded_tx_hash=tx_hash` are set
    :param safe_address: safe account
    :param retry: if True, retries are allowed, otherwise don't retry
    """

    safe_contract = SafeContract.objects.get(address=safe_address)
    try:
        safe_creation = SafeCreation.objects.get(safe=safe_address)
    except SafeCreation.DoesNotExist:
        deploy_create2_safe_task.delay(safe_address)
        return

    deployer_address = safe_creation.deployer
    payment = safe_creation.payment

    # These asserts just to make sure we are not wasting money
    assert check_checksum(safe_address)
    assert check_checksum(deployer_address)
    assert checksum_encode(mk_contract_address(sender=deployer_address, nonce=0)) == safe_address
    assert payment > 0

    redis = RedisRepository().redis
    with redis.lock('locks:fund_deployer_task', timeout=LOCK_TIMEOUT):
        ethereum_client = EthereumClientProvider()
        safe_funding, _ = SafeFunding.objects.get_or_create(safe=safe_contract)

        # Nothing to do if everything is funded and mined
        if safe_funding.is_all_funded():
            logger.debug('Nothing to do here for safe %s. Is all funded', safe_address)
            return

        # If receipt exists already, let's check
        if safe_funding.deployer_funded_tx_hash and not safe_funding.deployer_funded:
            logger.debug('Safe %s deployer has already been funded. Checking tx_hash %s',
                         safe_address,
                         safe_funding.deployer_funded_tx_hash)
            check_deployer_funded_task.delay(safe_address)
        elif not safe_funding.deployer_funded:
            confirmations = settings.SAFE_FUNDING_CONFIRMATIONS
            last_block_number = ethereum_client.current_block_number

            assert (last_block_number - confirmations) > 0

            if safe_creation.payment_token and safe_creation.payment_token != NULL_ADDRESS:
                safe_balance = ethereum_client.erc20.get_balance(safe_address, safe_creation.payment_token)
            else:
                safe_balance = ethereum_client.get_balance(safe_address, last_block_number - confirmations)

            if safe_balance >= payment:
                logger.info('Found %d balance for safe=%s', safe_balance, safe_address)
                safe_funding.safe_funded = True
                safe_funding.save()

                # Check deployer has no eth. This should never happen
                balance = ethereum_client.get_balance(deployer_address)
                if balance:
                    logger.error('Deployer=%s for safe=%s has eth already (%d wei)',
                                 deployer_address, safe_address, balance)
                else:
                    logger.info('Safe=%s. Transferring deployment-cost=%d to deployer=%s',
                                safe_address, safe_creation.wei_deploy_cost(), deployer_address)
                    tx_hash = FundingServiceProvider().send_eth_to(deployer_address,
                                                                   safe_creation.wei_deploy_cost(),
                                                                   gas_price=safe_creation.gas_price,
                                                                   retry=True)
                    if tx_hash:
                        tx_hash = tx_hash.hex()
                        logger.info('Safe=%s. Transferred deployment-cost=%d to deployer=%s with tx-hash=%s',
                                    safe_address, safe_creation.wei_deploy_cost(), deployer_address, tx_hash)
                        safe_funding.deployer_funded_tx_hash = tx_hash
                        safe_funding.save()
                        logger.debug('Safe=%s deployer has just been funded. tx_hash=%s', safe_address, tx_hash)
                        check_deployer_funded_task.apply_async((safe_address,), countdown=20)
                    else:
                        logger.error('Cannot send payment=%d to deployer safe=%s', payment, deployer_address)
                        if retry:
                            raise self.retry(countdown=30)
            else:
                logger.info('Not found required balance=%d for safe=%s', payment, safe_address)
                if retry:
                    raise self.retry(countdown=30)
예제 #25
0
    def test_safe_creation_with_payment_token(self):
        s = generate_valid_s()
        owner1, _ = get_eth_address_with_key()
        owner2, _ = get_eth_address_with_key()
        payment_token, _ = get_eth_address_with_key()
        serializer = SafeCreationSerializer(
            data={
                's': s,
                'owners': [owner1, owner2],
                'threshold': 2,
                'payment_token': payment_token,
            })
        self.assertTrue(serializer.is_valid())
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code,
                         status.HTTP_422_UNPROCESSABLE_ENTITY)
        response_json = response.json()
        self.assertIn('InvalidPaymentToken', response_json['exception'])
        self.assertIn(payment_token, response_json['exception'])

        # With previous versions of ganache it failed, because token was on DB but not in blockchain,
        # so gas cannot be estimated. With new versions of ganache estimation is working
        token_model = TokenFactory(address=payment_token,
                                   fixed_eth_conversion=0.1)
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        erc20_contract = self.deploy_example_erc20(10000, NULL_ADDRESS)
        payment_token = erc20_contract.address
        serializer = SafeCreationSerializer(
            data={
                's': s,
                'owners': [owner1, owner2],
                'threshold': 2,
                'payment_token': payment_token,
            })
        self.assertTrue(serializer.is_valid())
        token_model = TokenFactory(address=payment_token,
                                   fixed_eth_conversion=0.1)
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)

        response_json = response.json()
        deployer = response_json['deployer']
        self.assertTrue(check_checksum(deployer))
        self.assertTrue(check_checksum(response_json['safe']))
        self.assertEqual(response_json['paymentToken'], payment_token)

        self.assertTrue(
            SafeContract.objects.filter(address=response.data['safe']))
        safe_creation = SafeCreation.objects.get(deployer=deployer)
        self.assertIn(owner1, safe_creation.owners)
        self.assertEqual(safe_creation.payment_token, payment_token)
        self.assertGreater(safe_creation.payment,
                           safe_creation.wei_deploy_cost())

        # Check that payment is more than with ether
        token_payment = response_json['payment']
        serializer = SafeCreationSerializer(data={
            's': s,
            'owners': [owner1, owner2],
            'threshold': 2,
        })
        self.assertTrue(serializer.is_valid())
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        payment_using_ether = response_json['payment']
        self.assertGreater(token_payment, payment_using_ether)

        # Check that token with fixed conversion price to 1 is a little higher than with ether
        # (We need to pay for storage for token transfer, as funder does not own any token yet)
        erc20_contract = self.deploy_example_erc20(10000, NULL_ADDRESS)
        payment_token = erc20_contract.address
        token_model = TokenFactory(address=payment_token,
                                   fixed_eth_conversion=1)
        serializer = SafeCreationSerializer(
            data={
                's': s,
                'owners': [owner1, owner2],
                'threshold': 2,
                'payment_token': payment_token
            })
        self.assertTrue(serializer.is_valid())
        response = self.client.post(reverse('v1:safe-creation'),
                                    data=serializer.data,
                                    format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        response_json = response.json()
        deployer = response_json['deployer']
        payment_using_token = response_json['payment']
        self.assertGreater(payment_using_token, payment_using_ether)
        safe_creation = SafeCreation.objects.get(deployer=deployer)
        # Payment includes also the gas to send ether to the safe deployer
        self.assertGreater(safe_creation.payment,
                           safe_creation.wei_deploy_cost())
예제 #26
0
def circles_onboarding_safe_task(self, safe_address: str) -> None:
    """
    Check if create2 Safe has enough incoming trust connections to fund and
    deploy it
    :param safe_address: Address of the safe to-be-created
    """

    assert check_checksum(safe_address)

    try:
        redis = RedisRepository().redis
        lock_name = f'locks:circles_onboarding_safe_task:{safe_address}'
        with redis.lock(lock_name, blocking_timeout=1, timeout=LOCK_TIMEOUT):
            logger.info('Check deploying Safe .. {}'.format(safe_address))
            try:
                SafeCreationServiceProvider().deploy_create2_safe_tx(
                    safe_address)
            except SafeCreation2.DoesNotExist:
                pass
            except NotEnoughFundingForCreation:
                logger.info('Safe does not have enough fund for deployment, '
                            'check trust connections {}'.format(safe_address))
                # If we have enough trust connections, fund safe
                if GraphQLService().check_trust_connections(safe_address):
                    logger.info(
                        'Fund Safe deployment for {}'.format(safe_address))
                    ethereum_client = EthereumClientProvider()
                    safe_creation = SafeCreation2.objects.get(
                        safe=safe_address)
                    # Estimate costs of safe creation
                    safe_deploy_cost = safe_creation.wei_estimated_deploy_cost(
                    )
                    logger.info('Estimating %d for safe creation',
                                safe_deploy_cost)
                    # Estimate costs of token creation
                    transaction_service = TransactionServiceProvider()
                    token_deploy_cost = transaction_service.estimate_circles_signup_tx(
                        safe_address)
                    logger.info('Estimating %d for token deployment',
                                token_deploy_cost)
                    # Find total onboarding costs
                    payment = safe_deploy_cost + token_deploy_cost
                    # Get current safe balance
                    safe_balance = ethereum_client.get_balance(safe_address)
                    logger.info(
                        'Found %d balance for token deployment of safe=%s. Required=%d',
                        safe_balance, safe_address, payment)
                    if safe_balance >= payment:
                        logger.info('Onboarding is already funded {}'.format(
                            safe_address))
                        return

                    FundingServiceProvider().send_eth_to(safe_address,
                                                         payment,
                                                         gas=24000)
                    # Retry later to check for enough funding and successful deployment
                    raise self.retry(countdown=30)
                else:
                    logger.info(
                        'Not enough trust connections for funding deployment {}'
                        .format(safe_address))
    except LockError:
        pass
예제 #27
0
 def pack_address(self, address):
     assert check_checksum(address)
     return "000000000000000000000000" + address[2:]
예제 #28
0
lower = ['a', 'b', 'c', 'd', 'e']
startIndex = 17
endIndex = 27  #start with 0x, so indices [17,27) is the middle 10 letters

LETTERS = 22
MAX = (
    endIndex - startIndex
) * LETTERS  # there are 10 positions to replace, and every position has 22(0-9,a-f,A-F) possible symbols. We only replace one symbol, so there are 22*10=220 possible choices. Of course, some of them are invalid (such as replacing "a" by "a", that can be filtered later).
replacingSequence = list(range(
    0, MAX))  # generate a sequence from 0 to 219 to represent 220 choices.
random.shuffle(
    replacingSequence
)  # Shuffle the sequence to make the search be random. It doesn't matter if don't shuffle.

originalAddress = sys.argv[1]  # get the input from command line
if not check_checksum(originalAddress):
    print("Invalid EIP55 address")  #check whether the input is valid
else:
    found = False
    k = 0
    replacedAddress = ""
    while not found and k < MAX:

        position = startIndex + replacingSequence[
            k] // LETTERS  #we use number 0 to 219 to represent replacing choices. Here we map the number to the choice, i.e. the position and the letter
        replacedLetter = letterList[replacingSequence[k] % LETTERS]

        originalLetter = originalAddress[position]
        #print(k,position,originalLetter,replacedLetter)

        if replacedLetter.lower() != originalLetter.lower(