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()
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)
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)
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), )
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'
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)
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
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()))
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:]
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
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)
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
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}, )
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
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")
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
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)
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
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" )
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)
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)
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())
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
def pack_address(self, address): assert check_checksum(address) return "000000000000000000000000" + address[2:]
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(