コード例 #1
0
def get_eth2_balances(
        beaconchain: 'BeaconChain',
        addresses: List[ChecksumEthAddress],
) -> Dict[ChecksumEthAddress, Balance]:
    """May Raise RemoteError from beaconcha.in api"""
    address_to_validators = {}
    index_to_address = {}
    validator_indices = []
    usd_price = Inquirer().find_usd_price(A_ETH)
    balance_mapping: Dict[ChecksumEthAddress, Balance] = defaultdict(Balance)
    # Map eth1 addresses to validators
    for address in addresses:
        validators = beaconchain.get_eth1_address_validators(address)
        if len(validators) == 0:
            continue

        address_to_validators[address] = validators
        for validator in validators:
            validator_indices.append(validator.validator_index)
            index_to_address[validator.validator_index] = address

    # Get current balance of all validator indices
    performance = beaconchain.get_performance(validator_indices)
    for validator_index, entry in performance.items():
        amount = from_gwei(entry.balance)
        balance_mapping[index_to_address[validator_index]] += Balance(amount, amount * usd_price)

    # The performance call does not return validators that are not active and are still depositing
    depositing_indices = set(index_to_address.keys()) - set(performance.keys())
    for index in depositing_indices:
        balance_mapping[index_to_address[index]] += Balance(
            amount=FVal('32'), usd_value=FVal('32') * usd_price,
        )

    return balance_mapping
コード例 #2
0
ファイル: eth2_utils.py プロジェクト: nerevu/headless-rotki
def _serialize_gwei_with_price(value: int,
                               eth_usd_price: FVal) -> Dict[str, str]:
    normalized_value = from_gwei(value)
    return {
        'amount': str(normalized_value),
        'usd_value': str(normalized_value * eth_usd_price),
    }
コード例 #3
0
ファイル: eth2.py プロジェクト: zachmeador/rotki
def _get_eth2_staking_deposits_onchain(
    ethereum: 'EthereumManager',
    addresses: List[ChecksumEthAddress],
    has_premium: bool,
    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)
                amount = int.from_bytes(decoded_data[2], byteorder='little')
                usd_price = ZERO
                if has_premium:  # won't show this to non-premium so don't bother
                    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(),
                        withdrawal_credentials='0x' + decoded_data[1].hex(),
                        value=Balance(normalized_amount,
                                      usd_price * normalized_amount),
                        validator_index=int.from_bytes(decoded_data[4],
                                                       byteorder='little'),
                        tx_hash=tx_hash,
                        log_index=event['logIndex'],
                        timestamp=Timestamp(transaction.timestamp),
                    ))
                break

    return deposits
コード例 #4
0
    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
コード例 #5
0
    def get_balances(
        self,
        addresses: List[ChecksumEthAddress],
        fetch_validators_for_eth1: bool,
    ) -> Dict[Eth2PubKey, Balance]:
        """
        Returns a mapping of validator public key to eth balance.
        If fetch_validators_for_eth1 is true then each eth1 address is also checked
        for the validators it has deposited and the deposits are fetched.

        May Raise:
        - RemoteError from beaconcha.in api
        """
        usd_price = Inquirer().find_usd_price(A_ETH)
        dbeth2 = DBEth2(self.database)
        balance_mapping: Dict[Eth2PubKey, Balance] = defaultdict(Balance)
        validators: Union[List[ValidatorID], List[Eth2Validator]]
        if fetch_validators_for_eth1:
            validators = self.fetch_eth1_validator_data(addresses)
        else:
            validators = dbeth2.get_validators()

        if validators == []:
            return {}  # nothing detected

        pubkeys = []
        index_to_pubkey = {}
        index_to_ownership = {}
        for validator in validators:
            # create a mapping of indices to pubkeys since the performance call returns indices
            if validator.index is not None:
                index_to_pubkey[validator.index] = validator.public_key
                pubkeys.append(validator.public_key)
            index_to_ownership[
                validator.index] = validator.ownership_proportion

        # Get current balance of all validators. This may miss some balance if it's
        # in the deposit queue but it's too much work to get it right and should be
        # visible as soon as deposit clears the queue
        performance = self.beaconchain.get_performance(pubkeys)
        for validator_index, entry in performance.items():
            pubkey = index_to_pubkey.get(validator_index)
            if pubkey is None:
                log.error(
                    f'At eth2 get_balances could not find matching pubkey for validator index {validator_index}'
                )  # noqa: E501
                continue  # should not happen
            ownership_proportion = index_to_ownership.get(validator_index, ONE)
            amount = from_gwei(entry.balance) * ownership_proportion
            balance_mapping[pubkey] += Balance(amount, amount *
                                               usd_price)  # noqa: E501

        return balance_mapping
コード例 #6
0
ファイル: eth2.py プロジェクト: step21/rotki
    def get_balances(
        self,
        addresses: List[ChecksumEthAddress],
    ) -> Dict[ChecksumEthAddress, Balance]:
        """May Raise RemoteError from beaconcha.in api"""
        address_to_validators = {}
        index_to_address = {}
        validator_indices = []
        usd_price = Inquirer().find_usd_price(A_ETH)
        balance_mapping: Dict[ChecksumEthAddress,
                              Balance] = defaultdict(Balance)
        # Map eth1 addresses to validators
        for address in addresses:
            validators = self.beaconchain.get_eth1_address_validators(address)
            if len(validators) == 0:
                continue

            address_to_validators[address] = validators
            for validator in validators:
                if validator.validator_index is not None:
                    validator_indices.append(validator.validator_index)
                    index_to_address[validator.validator_index] = address
                else:
                    # Validator is early in depositing, and no index is known yet.
                    # Simply count 32 ETH balance for them
                    balance_mapping[address] += Balance(
                        amount=FVal('32'),
                        usd_value=FVal('32') * usd_price,
                    )

        # Get current balance of all validator indices
        performance = self.beaconchain.get_performance(validator_indices)
        for validator_index, entry in performance.items():
            amount = from_gwei(entry.balance)
            balance_mapping[index_to_address[validator_index]] += Balance(
                amount, amount * usd_price)  # noqa: E501

        # Performance call does not return validators that are not active and are still depositing
        # So for them let's just count 32 ETH
        depositing_indices = set(index_to_address.keys()) - set(
            performance.keys())
        for index in depositing_indices:
            balance_mapping[index_to_address[index]] += Balance(
                amount=FVal('32'),
                usd_value=FVal('32') * usd_price,
            )

        return balance_mapping
コード例 #7
0
ファイル: eth2.py プロジェクト: step21/rotki
    def _get_eth2_staking_deposits_onchain(
        self,
        addresses: List[ChecksumEthAddress],
        msg_aggregator: MessagesAggregator,
        from_ts: Timestamp,
        to_ts: Timestamp,
    ) -> List[Eth2Deposit]:
        from_block = max(
            ETH2_DEPOSIT.deployed_block,
            self.ethereum.get_blocknumber_by_time(from_ts),
        )
        to_block = self.ethereum.get_blocknumber_by_time(to_ts)
        events = ETH2_DEPOSIT.get_logs(
            ethereum=self.ethereum,
            event_name='DepositEvent',
            argument_filters={},
            from_block=from_block,
            to_block=to_block,
        )
        transactions = self.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