def handle(self, *args, **options): for task in TASKS: _, created = task.create_task() if created: self.stdout.write( self.style.SUCCESS('Created Periodic Task %s' % task.name)) else: self.stdout.write( self.style.SUCCESS('Task %s was already created' % task.name)) self.stdout.write( self.style.SUCCESS('Setting up Safe Contract Addresses')) ethereum_client = EthereumClientProvider() ethereum_network = ethereum_client.get_network() if ethereum_network in MASTER_COPIES: self.stdout.write( self.style.SUCCESS( f'Setting up {ethereum_network.name} safe addresses')) self._setup_safe_master_copies(MASTER_COPIES[ethereum_network]) if ethereum_network in PROXY_FACTORIES: self.stdout.write( self.style.SUCCESS( f'Setting up {ethereum_network.name} proxy factory addresses' )) self._setup_safe_proxy_factories(PROXY_FACTORIES[ethereum_network]) if not (ethereum_network in MASTER_COPIES and ethereum_network in PROXY_FACTORIES): self.stdout.write( self.style.WARNING('Cannot detect a valid ethereum-network'))
def handle(self, *args, **options): ethereum_client = EthereumClientProvider() proxy_factory_address = settings.SAFE_PROXY_FACTORY_ADDRESS deployer_key = options['deployer_key'] deployer_account = Account.privateKeyToAccount( deployer_key) if deployer_key else self.DEFAULT_ACCOUNT self.stdout.write( self.style.SUCCESS( 'Checking if proxy factory was already deployed on %s' % proxy_factory_address)) if ethereum_client.is_contract(proxy_factory_address): self.stdout.write( self.style.NOTICE('Proxy factory was already deployed on %s' % proxy_factory_address)) else: self.stdout.write( self.style.SUCCESS( 'Deploying proxy factory using deployer account, ' 'proxy factory %s not found' % proxy_factory_address)) proxy_factory_address = ProxyFactory.deploy_proxy_factory_contract( ethereum_client, deployer_account=deployer_account).contract_address self.stdout.write( self.style.SUCCESS('Proxy factory has been deployed on %s' % proxy_factory_address))
def fix_ethereum_logs(apps, schema_editor): EthereumTx = apps.get_model('history', 'EthereumTx') ethereum_client = EthereumClientProvider() # We need to add `address` to the logs, so we exclude empty logs and logs already containing `address` queryset = EthereumTx.objects.exclude(logs__0__has_key='address').exclude( logs=[]) total = queryset.count() processed = 200 logger.info('Fixing ethereum logs. %d remaining to be fixed', total) while True: ethereum_txs = queryset[:processed] if not ethereum_txs: break tx_hashes = [ethereum_tx.tx_hash for ethereum_tx in ethereum_txs] try: tx_receipts = ethereum_client.get_transaction_receipts(tx_hashes) for ethereum_tx, tx_receipt in zip(ethereum_txs, tx_receipts): ethereum_tx.logs = [ clean_receipt_log(log) for log in tx_receipt['logs'] ] ethereum_tx.save(update_fields=['logs']) total -= 1 logger.info('Fixed %d ethereum logs. %d remaining to be fixed', processed, total) except IOError: logger.warning('Node connection error when retrieving tx receipts')
def handle(self, *args, **options): fix = options['fix'] queryset = SafeStatus.objects.last_for_every_address() count = queryset.count() batch = 200 ethereum_client = EthereumClientProvider() index_service = IndexServiceProvider() for i in range(0, count, batch): self.stdout.write(self.style.SUCCESS(f'Processed {i}/{count}')) safe_statuses = queryset[i:i + batch] addresses = [] nonces = [] for result in safe_statuses.values('address', 'nonce'): addresses.append(result['address']) nonces.append(result['nonce']) blockchain_nonce_payloads = self.build_nonce_payload(addresses) blockchain_nonces = ethereum_client.batch_call_custom(blockchain_nonce_payloads) addresses_to_reindex = [] for address, nonce, blockchain_nonce in zip(addresses, nonces, blockchain_nonces): if nonce != blockchain_nonce: self.stdout.write(self.style.WARNING(f'Safe={address} stored nonce={nonce} is ' f'different from blockchain-nonce={blockchain_nonce}')) addresses_to_reindex.append(address) if fix and addresses_to_reindex: self.stdout.write(self.style.SUCCESS(f'Fixing Safes={addresses_to_reindex}')) index_service.reindex_addresses(addresses_to_reindex)
def handle(self, *args, **options): for task in self.tasks: _, created = task.create_task() if created: self.stdout.write(self.style.SUCCESS('Created Periodic Task %s' % task.name)) else: self.stdout.write(self.style.SUCCESS('Task %s was already created' % task.name)) self.stdout.write(self.style.SUCCESS('Setting up Safe Contract Addresses')) ethereum_client = EthereumClientProvider() ethereum_network = ethereum_client.get_network() self.stdout.write(self.style.SUCCESS('Network %s was identified' % ethereum_network)) if ethereum_network == EthereumNetwork.MAINNET: self.stdout.write(self.style.SUCCESS('Setting up Mainnet addresses')) self.setup_mainnet() elif ethereum_network == EthereumNetwork.RINKEBY: self.stdout.write(self.style.SUCCESS('Setting up Rinkeby addresses')) self.setup_rinkeby() elif ethereum_network == EthereumNetwork.GOERLI: self.stdout.write(self.style.SUCCESS('Setting up Goerli addresses')) self.setup_goerli() elif ethereum_network == EthereumNetwork.KOVAN: self.stdout.write(self.style.SUCCESS('Setting up Kovan addresses')) self.setup_kovan() elif ethereum_network == EthereumNetwork.UNKNOWN: self.stdout.write(self.style.SUCCESS('Setting up RSK addresses')) self.setup_rsk() else: self.stdout.write(self.style.WARNING(f'Cannot detect a valid ethereum-network'))
def check_create2_deployed_safes_task() -> None: """ Check if create2 safes were deployed and store the `blockNumber` if there are enough confirmations """ try: redis = RedisRepository().redis with redis.lock('tasks:check_create2_deployed_safes_task', blocking_timeout=1, timeout=LOCK_TIMEOUT): ethereum_client = EthereumClientProvider() confirmations = 6 current_block_number = ethereum_client.current_block_number for safe_creation2 in SafeCreation2.objects.pending_to_check(): tx_receipt = ethereum_client.get_transaction_receipt(safe_creation2.tx_hash) safe_address = safe_creation2.safe.address if tx_receipt: block_number = tx_receipt.blockNumber if (current_block_number - block_number) >= confirmations: logger.info('Safe=%s with tx-hash=%s was confirmed in block-number=%d', safe_address, safe_creation2.tx_hash, block_number) send_create_notification.delay(safe_address, safe_creation2.owners) safe_creation2.block_number = block_number safe_creation2.save() else: # If safe was not included in any block after 35 minutes (mempool limit is 30), we try to deploy it again if safe_creation2.modified + timedelta(minutes=35) < timezone.now(): logger.info('Safe=%s with tx-hash=%s was not deployed after 10 minutes', safe_address, safe_creation2.tx_hash) safe_creation2.tx_hash = None safe_creation2.save() deploy_create2_safe_task.delay(safe_address, retry=False) for safe_creation2 in SafeCreation2.objects.not_deployed(): deploy_create2_safe_task.delay(safe_creation2.safe.address, retry=False) except LockError: pass
def handle(self, *args, **options): ethereum_client = EthereumClientProvider() app_name = apps.get_app_config('history').verbose_name network_name = ethereum_client.get_network().name.capitalize() startup_message = f'Starting {app_name} version {__version__} on {network_name}' self.stdout.write(self.style.SUCCESS(startup_message)) if settings.SLACK_API_WEBHOOK: try: r = requests.post(settings.SLACK_API_WEBHOOK, json={'text': startup_message}) if r.ok: self.stdout.write( self.style.SUCCESS( f'Slack configured, "{startup_message}" sent')) else: raise RequestException() except RequestException as e: self.stdout.write( self.style.ERROR( f'Cannot send slack notification to webhook ' f'({settings.SLACK_API_WEBHOOK}): "{e}"')) else: self.stdout.write( self.style.SUCCESS('Slack not configured, ignoring'))
def handle(self, *args, **options): ethereum_client = EthereumClientProvider() total = EthereumTx.objects.filter(logs=None).count() processed = 200 self.stdout.write( self.style.SUCCESS( f'Fixing ethereum logs. {total} remaining to be fixed')) while True: ethereum_txs = EthereumTx.objects.filter(logs=None)[:processed] if not ethereum_txs: break tx_hashes = [ethereum_tx.tx_hash for ethereum_tx in ethereum_txs] tx_receipts = ethereum_client.get_transaction_receipts(tx_hashes) for ethereum_tx, tx_receipt in zip(ethereum_txs, tx_receipts): ethereum_tx.logs = [ clean_receipt_log(log) for log in tx_receipt['logs'] ] ethereum_tx.save(update_fields=['logs']) total -= 1 self.stdout.write( self.style.SUCCESS( f'Fixed {processed} ethereum logs. {total} remaining to be fixed' ))
def add_status_and_index_to_txs(apps, schema_editor): EthereumTx = apps.get_model("relay", "EthereumTx") ethereum_client = EthereumClientProvider() for ethereum_tx in EthereumTx.objects.filter(status=None): tx_receipt = ethereum_client.get_transaction_receipt(ethereum_tx.tx_hash) if tx_receipt: ethereum_tx.status = tx_receipt.get("status") ethereum_tx.transaction_index = tx_receipt["transactionIndex"] ethereum_tx.save(update_fields=["status", "transaction_index"])
def add_status_and_index_to_txs(apps, schema_editor): EthereumTx = apps.get_model('relay', 'EthereumTx') ethereum_client = EthereumClientProvider() for ethereum_tx in EthereumTx.objects.filter(status=None): tx_receipt = ethereum_client.get_transaction_receipt(ethereum_tx.tx_hash) if tx_receipt: ethereum_tx.status = tx_receipt.get('status') ethereum_tx.transaction_index = tx_receipt['transactionIndex'] ethereum_tx.save(update_fields=['status', 'transaction_index'])
def get_or_create_from_block_number(self, block_number: int): try: return self.get(number=block_number) except self.model.DoesNotExist: ethereum_client = EthereumClientProvider() current_block_number = ethereum_client.current_block_number # For reorgs block = ethereum_client.get_block(block_number) return self.create_from_block( block, current_block_number=current_block_number)
def handle(self, *args, **options): fix = options['fix'] queryset = SafeStatus.objects.last_for_every_address() count = queryset.count() batch = 100 ethereum_client = EthereumClientProvider() index_service = IndexServiceProvider() for i in range(0, count, batch): self.stdout.write(self.style.SUCCESS(f'Processed {i}/{count}')) safe_statuses = queryset[i:i + batch] safe_statuses_list = list( safe_statuses) # Force retrieve queryset from DB blockchain_nonce_payloads = self.build_nonce_payload( [safe_status.address for safe_status in safe_statuses_list]) blockchain_nonces = ethereum_client.batch_call_custom( blockchain_nonce_payloads, raise_exception=False) addresses_to_reindex = set() for safe_status, blockchain_nonce in zip(safe_statuses_list, blockchain_nonces): address = safe_status.address nonce = safe_status.nonce if safe_status.is_corrupted(): self.stdout.write( self.style.WARNING( f'Safe={address} is corrupted, has some old ' f'transactions missing')) addresses_to_reindex.add(address) if blockchain_nonce is None: self.stdout.write( self.style.WARNING( f'Safe={address} looks problematic, ' f'cannot retrieve blockchain-nonce')) if nonce != blockchain_nonce: self.stdout.write( self.style.WARNING( f'Safe={address} stored nonce={nonce} is ' f'different from blockchain-nonce={blockchain_nonce}' )) if last_valid_transaction := MultisigTransaction.objects.last_valid_transaction( address): self.stdout.write( self.style.WARNING( f'Last valid transaction for Safe={address} has safe-nonce={last_valid_transaction.nonce} ' f'safe-transaction-hash={last_valid_transaction.safe_tx_hash} and ' f'ethereum-tx-hash={last_valid_transaction.ethereum_tx_id}' )) addresses_to_reindex.add(address) if fix and addresses_to_reindex: self.stdout.write( self.style.SUCCESS(f'Fixing Safes={addresses_to_reindex}')) index_service.reindex_addresses(addresses_to_reindex)
def check_deployer_funded_task(self, safe_address: str, retry: bool = True) -> None: """ Check the `deployer_funded_tx_hash`. If receipt can be retrieved, in SafeFunding `deployer_funded=True`. If not, after the number of retries `deployer_funded_tx_hash=None` :param safe_address: safe account :param retry: if True, retries are allowed, otherwise don't retry """ try: redis = RedisRepository().redis with redis.lock(f"tasks:check_deployer_funded_task:{safe_address}", blocking_timeout=1, timeout=LOCK_TIMEOUT): ethereum_client = EthereumClientProvider() logger.debug('Starting check deployer funded task for safe=%s', safe_address) safe_funding = SafeFunding.objects.get(safe=safe_address) deployer_funded_tx_hash = safe_funding.deployer_funded_tx_hash if safe_funding.deployer_funded: logger.warning('Tx-hash=%s for safe %s is already checked', deployer_funded_tx_hash, safe_address) return elif not deployer_funded_tx_hash: logger.error('No deployer_funded_tx_hash for safe=%s', safe_address) return logger.debug('Checking safe=%s deployer tx-hash=%s', safe_address, deployer_funded_tx_hash) if ethereum_client.get_transaction_receipt(deployer_funded_tx_hash): logger.info('Found transaction to deployer of safe=%s with receipt=%s', safe_address, deployer_funded_tx_hash) safe_funding.deployer_funded = True safe_funding.save() else: logger.debug('Not found transaction receipt for tx-hash=%s', deployer_funded_tx_hash) # If no more retries if not retry or (self.request.retries == self.max_retries): safe_creation = SafeCreation.objects.get(safe=safe_address) balance = ethereum_client.get_balance(safe_creation.deployer) if balance >= safe_creation.wei_deploy_cost(): logger.warning('Safe=%s. Deployer=%s. Cannot find transaction receipt with tx-hash=%s, ' 'but balance is there. This should never happen', safe_address, safe_creation.deployer, deployer_funded_tx_hash) safe_funding.deployer_funded = True safe_funding.save() else: logger.error('Safe=%s. Deployer=%s. Transaction receipt with tx-hash=%s not mined after %d ' 'retries. Setting `deployer_funded_tx_hash` back to `None`', safe_address, safe_creation.deployer, deployer_funded_tx_hash, self.request.retries) safe_funding.deployer_funded_tx_hash = None safe_funding.save() else: logger.debug('Retry finding transaction receipt %s', deployer_funded_tx_hash) if retry: raise self.retry(countdown=self.request.retries * 10 + 15) # More countdown every retry except LockError: logger.info('check_deployer_funded_task is locked for safe=%s', safe_address)
def fix_uniswap_pool_tokens_task() -> Optional[int]: ethereum_client = EthereumClientProvider() ethereum_network = ethereum_client.get_network() if ethereum_network == EthereumNetwork.MAINNET: try: number = Token.objects.fix_uniswap_pool_tokens() if number: logger.info('%d uniswap pool token names were fixed', number) return number finally: close_gevent_db_connection()
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 fix_pool_tokens_task() -> Optional[int]: """ Fix names for generic pool tokens, like Balancer or Uniswap :return: Number of pool token names updated """ ethereum_client = EthereumClientProvider() ethereum_network = ethereum_client.get_network() if ethereum_network == EthereumNetwork.MAINNET: try: number = Token.pool_tokens.fix_all_pool_tokens() if number: logger.info('%d pool token names were fixed', number) return number finally: close_gevent_db_connection()
def handle(self, *args, **options): tokens = options['tokens'] no_prompt = options['no_prompt'] ethereum_client = EthereumClientProvider() for token_address in tokens: token_address = ethereum_client.w3.toChecksumAddress(token_address) try: token = Token.objects.get(address=token_address) self.stdout.write( self.style.SUCCESS( f'Token {token.name} - {token.symbol} with address ' f'{token_address} already exists')) continue except Token.DoesNotExist: pass info = ethereum_client.erc20.get_info(token_address) if no_prompt: response = 'y' else: response = input(f'Do you want to create a token {info} (y/n) ' ).strip().lower() if response == 'y': Token.objects.create(address=token_address, name=info.name, symbol=info.symbol, decimals=info.decimals) self.stdout.write( self.style.SUCCESS(f'Created token {info.name}'))
def validate(self, data): super().validate(data) safe_address = data["safe"] if not SafeContract.objects.filter(address=safe_address).exists(): raise ValidationError( f"Safe={safe_address} does not exist or it's still not indexed" ) signature = data["signature"] delegate = data["delegate"] # Delegate address to be added/removed ethereum_client = EthereumClientProvider() valid_delegators = self.get_valid_delegators(ethereum_client, safe_address, delegate) # Tries to find a valid delegator using multiple strategies for operation_hash in DelegateSignatureHelper.calculate_all_possible_hashes( delegate): delegator = self.check_signature( ethereum_client, safe_address, signature, operation_hash, valid_delegators, ) if delegator: break if not delegator: raise ValidationError("Signing owner is not an owner of the Safe") data["delegator"] = delegator return data
def handle(self, *args, **options): tokens = options['tokens'] no_prompt = options['no_prompt'] ethereum_client = EthereumClientProvider() for token_address in tokens: token_address = ethereum_client.w3.toChecksumAddress(token_address) try: token = Token.objects.get(address=token_address) self.stdout.write(self.style.SUCCESS(f'Token {token.name} - {token.symbol} with address ' f'{token_address} already exists')) if not token.trusted: # Mark token as trusted if it's not token.set_trusted() self.stdout.write(self.style.SUCCESS(f'Marking token {token_address} as trusted')) continue except Token.DoesNotExist: pass try: info = ethereum_client.erc20.get_info(token_address) decimals = info.decimals except InvalidERC20Info: # Try with a ERC721 info = ethereum_client.erc721.get_info(token_address) self.stdout.write(self.style.SUCCESS('Detected ERC721 token')) decimals = 0 if no_prompt: response = 'y' else: response = input(f'Do you want to create a token {info} (y/n) ').strip().lower() if response == 'y': Token.objects.create(address=token_address, name=info.name, symbol=info.symbol, decimals=decimals, trusted=True) self.stdout.write(self.style.SUCCESS(f'Created token {info.name} on address {token_address}'))
def __new__(cls): if not hasattr(cls, "instance"): from django.conf import settings cls.instance = ReorgService(EthereumClientProvider(), settings.ETH_REORG_BLOCKS) return cls.instance
def create_from_blockchain( self, token_address: ChecksumAddress) -> Optional['Token']: ethereum_client = EthereumClientProvider() if token_address in ENS_CONTRACTS_WITH_TLD: # Special case for ENS return self.create(address=token_address, name='Ethereum Name Service', symbol='ENS', logo_uri='ENS.png', decimals=None, trusted=True) try: logger.debug('Querying blockchain for info for erc20 token=%s', token_address) erc_info = ethereum_client.erc20.get_info(token_address) decimals = erc_info.decimals except InvalidERC20Info: logger.debug( 'Erc20 token not found, querying blockchain for info for erc721 token=%s', token_address) try: erc_info = ethereum_client.erc721.get_info(token_address) decimals = None except InvalidERC721Info: logger.debug('Cannot find anything on blockchain for token=%s', token_address) return None # If symbol is way bigger than name (by 5 characters), swap them (e.g. POAP) name, symbol = erc_info.name, erc_info.symbol if (len(name) - len(symbol)) < -5: name, symbol = symbol, name return self.create(address=token_address, name=name, symbol=symbol, decimals=decimals)
def fix_balancer_pool_tokens(self) -> int: """ All Uniswap V2 tokens have the same name: "Uniswap V2". This method will return better names :return: Number of pool tokens fixed """ zerion_client = BalancerTokenAdapterClient(EthereumClientProvider()) return self._fix_pool_tokens('Balancer Pool Token', zerion_client)
def validate(self, data): super().validate(data) if not SafeContract.objects.filter(address=data['safe']).exists(): raise ValidationError(f"Safe={data['safe']} does not exist or it's still not indexed") ethereum_client = EthereumClientProvider() safe = Safe(data['safe'], ethereum_client) # Check owners and pending owners try: safe_owners = safe.retrieve_owners(block_identifier='pending') except BadFunctionCallOutput: # Error using pending block identifier safe_owners = safe.retrieve_owners(block_identifier='latest') signature = data['signature'] delegate = data['delegate'] # Delegate address to be added # Tries to find a valid delegator using multiple strategies for operation_hash in (DelegateSignatureHelper.calculate_hash(delegate), DelegateSignatureHelper.calculate_hash(delegate, eth_sign=True), DelegateSignatureHelper.calculate_hash(delegate, previous_topt=True), DelegateSignatureHelper.calculate_hash(delegate, eth_sign=True, previous_topt=True)): delegator = self.check_signature(signature, operation_hash, safe_owners) if delegator: break if not delegator: raise ValidationError('Signing owner is not an owner of the Safe') data['delegator'] = delegator return data
def reindex_master_copies( self, from_block_number: int, to_block_number: Optional[int] = None, block_process_limit: int = 100, addresses: Optional[ChecksumAddress] = None, ): """ Reindexes master copies in parallel with the current running indexer, so service will have no missing txs while reindexing :param from_block_number: Block number to start indexing from :param to_block_number: Block number to stop indexing on :param block_process_limit: Number of blocks to process each time :param addresses: Master Copy or Safes(for L2 event processing) addresses. If not provided, all master copies will be used """ assert (not to_block_number) or to_block_number > from_block_number from ..indexers import ( EthereumIndexer, InternalTxIndexerProvider, SafeEventsIndexerProvider, ) indexer_provider = (SafeEventsIndexerProvider if self.eth_l2_network else InternalTxIndexerProvider) indexer: EthereumIndexer = indexer_provider() ethereum_client = EthereumClientProvider() if addresses: indexer.IGNORE_ADDRESSES_ON_LOG_FILTER = ( False # Just process addresses provided ) else: addresses = list( indexer.database_queryset.values_list("address", flat=True)) if not addresses: logger.warning("No addresses to process") else: logger.info("Start reindexing Safe Master Copy addresses %s", addresses) current_block_number = ethereum_client.current_block_number stop_block_number = (min(current_block_number, to_block_number) if to_block_number else current_block_number) block_number = from_block_number while block_number < stop_block_number: elements = indexer.find_relevant_elements( addresses, block_number, block_number + block_process_limit) indexer.process_elements(elements) block_number += block_process_limit logger.info( "Current block number %d, found %d traces/events", block_number, len(elements), ) logger.info("End reindexing addresses %s", addresses)
def save(self, **kwargs): safe_address = self.context['safe_address'] ethereum_client = EthereumClientProvider() safe = Safe(safe_address, ethereum_client) safe_tx_gas = safe.estimate_tx_gas(self.validated_data['to'], self.validated_data['value'], self.validated_data['data'], self.validated_data['operation']) return {'safe_tx_gas': safe_tx_gas}
def validate(self, data): super().validate(data) safe_address: Optional[ChecksumAddress] = data.get("safe") if (safe_address and not SafeContract.objects.filter( address=safe_address).exists()): raise ValidationError( f"Safe={safe_address} does not exist or it's still not indexed" ) signature = data["signature"] delegate = data["delegate"] # Delegate address to be added/removed delegator = data[ "delegator"] # Delegator giving permissions to delegate (signer) ethereum_client = EthereumClientProvider() if safe_address: # Valid delegators must be owners valid_delegators = self.get_safe_owners(ethereum_client, safe_address) if delegator not in valid_delegators: raise ValidationError( f"Provided delegator={delegator} is not an owner of Safe={safe_address}" ) # Tries to find a valid delegator using multiple strategies for operation_hash in DelegateSignatureHelper.calculate_all_possible_hashes( delegate): if self.check_delegate_signature(ethereum_client, signature, operation_hash, delegator): return data raise ValidationError( f"Signature does not match provided delegator={delegator}")
def validate_signature(self, signature: bytes): safe_tx_hash = self.context['safe_tx_hash'] try: multisig_transaction = MultisigTransaction.objects.select_related( 'ethereum_tx' ).get(safe_tx_hash=safe_tx_hash) except MultisigTransaction.DoesNotExist: raise NotFound(f'Multisig transaction with safe-tx-hash={safe_tx_hash} was not found') safe_address = multisig_transaction.safe if multisig_transaction.executed: raise ValidationError(f'Transaction with safe-tx-hash={safe_tx_hash} was already executed') ethereum_client = EthereumClientProvider() safe = Safe(safe_address, ethereum_client) try: safe_owners = safe.retrieve_owners(block_identifier='pending') except BadFunctionCallOutput: # Error using pending block identifier safe_owners = safe.retrieve_owners(block_identifier='latest') parsed_signatures = SafeSignature.parse_signature(signature, safe_tx_hash) signature_owners = [] for safe_signature in parsed_signatures: owner = safe_signature.owner if owner not in safe_owners: raise ValidationError(f'Signer={owner} is not an owner. Current owners={safe_owners}') if not safe_signature.is_valid(ethereum_client, safe.address): raise ValidationError(f'Signature={safe_signature.signature.hex()} for owner={owner} is not valid') if owner in signature_owners: raise ValidationError(f'Signature for owner={owner} is duplicated') signature_owners.append(owner) return signature
def queryset(self, request, queryset): current_block_number = EthereumClientProvider().current_block_number condition = {'erc20_block_number__gte': current_block_number - 200} if self.value() == 'YES': return queryset.filter(**condition) elif self.value() == 'NO': return queryset.exclude(**condition)
def __new__(cls): if not hasattr(cls, 'instance'): from django.conf import settings cls.instance = BalanceService(EthereumClientProvider(), settings.ETH_UNISWAP_FACTORY_ADDRESS, settings.ETH_KYBER_NETWORK_PROXY_ADDRESS) return cls.instance
def check_balance_of_accounts_task() -> bool: """ Checks if balance of relayer accounts (tx sender, safe funder) are less than the configured threshold :return: True if every account have enough ether, False otherwise """ balance_warning_wei = settings.SAFE_ACCOUNTS_BALANCE_WARNING addresses = FundingServiceProvider().funder_account.address, TransactionServiceProvider().tx_sender_account.address ethereum_client = EthereumClientProvider() result = True for address in addresses: balance_wei = ethereum_client.get_balance(address) if balance_wei <= balance_warning_wei: logger.error('Relayer account=%s current balance=%d . Balance must be greater than %d', address, balance_wei, balance_warning_wei) result = False return result