def get_eth2_deposits( self, from_ts: Optional[Timestamp] = None, to_ts: Optional[Timestamp] = None, address: Optional[ChecksumEthAddress] = None, ) -> List[Eth2Deposit]: """Returns a list of Eth2Deposit filtered by time and address""" cursor = self.db.conn.cursor() query = ( 'SELECT ' 'tx_hash, ' 'tx_index, ' 'from_address, ' 'timestamp, ' 'pubkey, ' 'withdrawal_credentials, ' 'amount, ' 'usd_value ' 'FROM eth2_deposits ' ) # Timestamp filters are omitted, done via `form_query_to_filter_timestamps` filters = [] if address is not None: filters.append(f'from_address="{address}" ') if filters: query += 'WHERE ' query += 'AND '.join(filters) query, bindings = form_query_to_filter_timestamps(query, 'timestamp', from_ts, to_ts) results = cursor.execute(query, bindings) return [Eth2Deposit.deserialize_from_db(deposit_tuple) for deposit_tuple in results]
def test_eth2_deposits_serialization(): addr1 = make_ethereum_address() addr2 = make_ethereum_address() deposits = [ Eth2Deposit( from_address=addr1, pubkey='0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 withdrawal_credentials='0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 value=Balance(FVal(32), FVal(64)), deposit_index=9, tx_hash='0xd9eca1c2a0c5ff2f25071713432b21cc4d0ff2e8963edc63a48478e395e08db1', log_index=22, timestamp=Timestamp(int(1604506685)), ), Eth2Deposit( from_address=addr2, pubkey='0xa8ff5fc88412d080a297683c25a791ef77eb52d75b265fabab1f2c2591bb927c35818ac6289bc6680ab252787d0ebab3', # noqa: E501 withdrawal_credentials='0x00cfe1c10347d642a8b8daf86d23bcb368076972691445de2cf517ff43765817', # noqa: E501 value=Balance(FVal(32), FVal(64)), deposit_index=1650, tx_hash='0x6905f4d1843fb8c003c1fbbc2c8e6c5f9792f4f44ddb1122553412ee0b128da7', log_index=221, timestamp=Timestamp(int(1605043544)), ), ] serialized = process_result_list(deposits) assert serialized == [ { 'from_address': addr1, 'pubkey': '0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 'withdrawal_credentials': '0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 'value': {'amount': '32', 'usd_value': '64'}, 'deposit_index': 9, 'tx_hash': '0xd9eca1c2a0c5ff2f25071713432b21cc4d0ff2e8963edc63a48478e395e08db1', 'log_index': 22, 'timestamp': 1604506685, }, { 'from_address': addr2, 'pubkey': '0xa8ff5fc88412d080a297683c25a791ef77eb52d75b265fabab1f2c2591bb927c35818ac6289bc6680ab252787d0ebab3', # noqa: E501 'withdrawal_credentials': '0x00cfe1c10347d642a8b8daf86d23bcb368076972691445de2cf517ff43765817', # noqa: E501 'value': {'amount': '32', 'usd_value': '64'}, 'deposit_index': 1650, 'tx_hash': '0x6905f4d1843fb8c003c1fbbc2c8e6c5f9792f4f44ddb1122553412ee0b128da7', 'log_index': 221, 'timestamp': 1605043544, }, ]
def get_validator_deposits( self, indices_or_pubkeys: Union[List[int], List[Eth2PubKey]], ) -> List[Eth2Deposit]: """Get the deposits of all the validators given from the list of indices or pubkeys Queries in chunks of 100 due to api limitations May raise: - RemoteError due to problems querying beaconcha.in API """ chunks = _calculate_query_chunks(indices_or_pubkeys) data = [] for chunk in chunks: result = self._query( module='validator', endpoint='deposits', encoded_args=','.join(str(x) for x in chunk), ) if isinstance(result, list): data.extend(result) else: data.append(result) deposits = [] for entry in data: try: amount = from_gwei(FVal(entry['amount'])) timestamp = entry['block_ts'] usd_price = query_usd_price_zero_if_error( asset=A_ETH, time=timestamp, location=f'Eth2 staking deposit at time {timestamp}', msg_aggregator=self.msg_aggregator, ) deposits.append( Eth2Deposit( from_address=deserialize_ethereum_address( entry['from_address']), pubkey=entry['publickey'], withdrawal_credentials=entry['withdrawal_credentials'], value=Balance( amount=amount, usd_value=amount * usd_price, ), tx_hash=hexstring_to_bytes(entry['tx_hash']), tx_index=entry['tx_index'], timestamp=entry['block_ts'], )) except (DeserializationError, KeyError) as e: msg = str(e) if isinstance(e, KeyError): msg = f'Missing key entry for {msg}.' raise RemoteError( f'Beaconchai.in deposits response processing error. {msg}', ) from e return deposits
def _get_eth2_staking_deposits_onchain( ethereum: 'EthereumManager', addresses: List[ChecksumEthAddress], msg_aggregator: MessagesAggregator, from_ts: Timestamp, to_ts: Timestamp, ) -> List[Eth2Deposit]: events = ETH2_DEPOSIT.get_logs( ethereum=ethereum, event_name='DepositEvent', argument_filters={}, from_block=ETH2_DEPOSIT.deployed_block, to_block='latest', ) transactions = ethereum.transactions.query( addresses=addresses, from_ts=from_ts, to_ts=to_ts, with_limit=False, recent_first=False, ) deposits: List[Eth2Deposit] = [] for transaction in transactions: if transaction.to_address != ETH2_DEPOSIT.address: continue tx_hash = '0x' + transaction.tx_hash.hex() for event in events: # Now find the corresponding event. If no event is found the transaction # probably failed or was something other than a deposit if event['transactionHash'] == tx_hash: decoded_data = decode_event_data(event['data'], EVENT_ABI) # all pylint ignores below due to https://github.com/PyCQA/pylint/issues/4114 amount = int.from_bytes(decoded_data[2], byteorder='little') # pylint: disable=unsubscriptable-object # noqa: E501 usd_price = query_usd_price_zero_if_error( asset=A_ETH, time=transaction.timestamp, location='Eth2 staking query', msg_aggregator=msg_aggregator, ) normalized_amount = from_gwei(FVal(amount)) deposits.append( Eth2Deposit( from_address=transaction.from_address, pubkey='0x' + decoded_data[0].hex(), # pylint: disable=unsubscriptable-object # noqa: E501 withdrawal_credentials='0x' + decoded_data[1].hex(), # pylint: disable=unsubscriptable-object # noqa: E501 value=Balance(normalized_amount, usd_price * normalized_amount), deposit_index=int.from_bytes(decoded_data[4], byteorder='little'), # pylint: disable=unsubscriptable-object # noqa: E501 tx_hash=tx_hash, log_index=event['logIndex'], timestamp=Timestamp(transaction.timestamp), )) break return deposits
'0xfeF0E7635281eF8E3B705e9C5B86e1d3B0eAb397') ADDR2 = deserialize_ethereum_address( '0x00F8a0D8EE1c21151BCcB416bCa1C152f9952D19') ADDR3 = deserialize_ethereum_address( '0x3266F3546a1e5Dc6A15588f3324741A0E20a3B6c') # List of ADDR1, ADDR2 and ADDR3 deposit events from 1604506685 to 1605044577 # sorted by (timestamp, log_index). EXPECTED_DEPOSITS = [ Eth2Deposit( from_address=ADDR1, pubkey= '0xb016e31f633a21fbe42a015152399361184f1e2c0803d89823c224994af74a561c4ad8cfc94b18781d589d03e952cd5b', # noqa: E501 withdrawal_credentials= '0x004c7691c2085648f394ffaef851f3b1d51b95f7263114bc923fc5338f5fc499', # noqa: E501 value=Balance(FVal(32), FVal(64)), deposit_index=9, tx_hash= '0xd9eca1c2a0c5ff2f25071713432b21cc4d0ff2e8963edc63a48478e395e08db1', log_index=22, timestamp=Timestamp(int(1604506685)), ), Eth2Deposit( from_address=ADDR3, pubkey= '0x90b2f65cb43d9cdb2279af9f76010d667b9d8d72e908f2515497a7102820ce6bb15302fe2b8dc082fce9718569344ad8', # noqa: E501 withdrawal_credentials= '0x00a257d19e1650dec1ab59fc9e1cb9a9fc2fe7265b0f27e7d79ff61aeff0a1f0', # noqa: E501 value=Balance(FVal(32), FVal(64)), deposit_index=993, tx_hash=