def _query_ethereum_tokens( self, action: AccountAction, given_accounts: Optional[List[ChecksumEthAddress]] = None, force_detection: bool = False, ) -> None: """Queries ethereum token balance via either etherscan or ethereum node By default queries all accounts but can also be given a specific list of accounts to query. Should come here during addition of a new account or querying of all token balances. May raise: - RemoteError if an external service such as Etherscan or cryptocompare is queried and there is a problem with its query. - EthSyncError if querying the token balances through a provided ethereum client and the chain is not synced """ if given_accounts is None: accounts = self.accounts.eth else: accounts = given_accounts ethtokens = EthTokens(database=self.database, ethereum=self.ethereum) try: balance_result, token_usd_price = ethtokens.query_tokens_for_addresses( addresses=accounts, force_detection=force_detection, ) except BadFunctionCallOutput as e: log.error( 'Assuming unsynced chain. Got web3 BadFunctionCallOutput ' 'exception: {}'.format(str(e)), ) raise EthSyncError( 'Tried to use the ethereum chain of the provided client to query ' 'token balances but the chain is not synced.', ) from e self._update_balances_after_token_query(action, balance_result, token_usd_price) # noqa: E501
def ethtokens(ethereum_manager, database): return EthTokens(database, ethereum_manager)
def _query_ethereum_tokens( self, action: AccountAction, given_accounts: Optional[List[ChecksumEthAddress]] = None, force_detection: bool = False, ) -> None: """Queries ethereum token balance via either etherscan or ethereum node By default queries all accounts but can also be given a specific list of accounts to query. Should come here during addition of a new account or querying of all token balances. May raise: - RemoteError if an external service such as Etherscan or cryptocompare is queried and there is a problem with its query. - EthSyncError if querying the token balances through a provided ethereum client and the chain is not synced """ if given_accounts is None: accounts = self.accounts.eth else: accounts = given_accounts ethtokens = EthTokens(database=self.database, ethereum=self.ethereum) try: balance_result, token_usd_price = ethtokens.query_tokens_for_addresses( addresses=accounts, force_detection=force_detection, ) except BadFunctionCallOutput as e: log.error( 'Assuming unsynced chain. Got web3 BadFunctionCallOutput ' 'exception: {}'.format(str(e)), ) raise EthSyncError( 'Tried to use the ethereum chain of the provided client to query ' 'token balances but the chain is not synced.', ) # Update the per account token balance and usd value token_totals: Dict[EthereumToken, FVal] = defaultdict(FVal) eth_balances = self.balances.eth for account, token_balances in balance_result.items(): for token, token_balance in token_balances.items(): if token_usd_price[token] == ZERO: # skip tokens that have no price continue token_totals[token] += token_balance usd_value = token_balance * token_usd_price[token] eth_balances[account].assets[token] = Balance( amount=token_balance, usd_value=usd_value, ) # Update the totals for token, token_total_balance in token_totals.items(): if action == AccountAction.QUERY: self.totals.assets[token] = Balance( amount=token_total_balance, usd_value=token_total_balance * token_usd_price[token], ) else: # addition self.totals.assets[token] += Balance( amount=token_total_balance, usd_value=token_total_balance * token_usd_price[token], )
def _query_ethereum_tokens( self, action: AccountAction, given_accounts: Optional[List[ChecksumEthAddress]] = None, force_detection: bool = False, ) -> None: """Queries ethereum token balance via either etherscan or ethereum node By default queries all accounts but can also be given a specific list of accounts to query. May raise: - RemoteError if an external service such as Etherscan or cryptocompare is queried and there is a problem with its query. - EthSyncError if querying the token balances through a provided ethereum client and the chain is not synced """ if given_accounts is None: accounts = self.accounts.eth else: accounts = given_accounts ethtokens = EthTokens(database=self.database, ethereum=self.ethereum) try: balance_result, token_usd_price = ethtokens.query_tokens_for_addresses( addresses=accounts, force_detection=force_detection, ) except BadFunctionCallOutput as e: log.error( 'Assuming unsynced chain. Got web3 BadFunctionCallOutput ' 'exception: {}'.format(str(e)), ) raise EthSyncError( 'Tried to use the ethereum chain of the provided client to query ' 'token balances but the chain is not synced.', ) add_or_sub: Optional[Callable[[Any, Any], Any]] if action == AccountAction.APPEND: add_or_sub = operator.add elif action == AccountAction.REMOVE: add_or_sub = operator.sub else: add_or_sub = None # Update the per account token balance and usd value token_totals: Dict[EthereumToken, FVal] = defaultdict(FVal) eth_balances = self.balances.eth for account, token_balances in balance_result.items(): for token, token_balance in token_balances.items(): if token_usd_price[token] == ZERO: # skip tokens that have no price continue token_totals[token] += token_balance if action == AccountAction.QUERY or action == AccountAction.APPEND: usd_value = token_balance * token_usd_price[token] eth_balances[account].asset_balances[token] = Balance( amount=token_balance, usd_value=usd_value, ) eth_balances[account].increase_total_usd_value(usd_value) # Update the totals for token, token_total_balance in token_totals.items(): if action == AccountAction.QUERY: self.totals[token] = Balance( amount=token_total_balance, usd_value=token_total_balance * token_usd_price[token], ) else: if action == AccountAction.REMOVE and token not in self.totals: # Removing the only account that holds this token self.totals[token] = Balance(amount=ZERO, usd_value=ZERO) else: new_amount = add_or_sub( self.totals[token].amount, token_total_balance) # type: ignore # noqa: E501 if new_amount <= ZERO: new_amount = ZERO new_usd_value = ZERO else: new_usd_value = add_or_sub( # type: ignore self.totals[token].usd_value, token_total_balance * token_usd_price[token], ) self.totals[token] = Balance( amount=new_amount, usd_value=new_usd_value, )
def _add_protocol_balances(self) -> None: """Also count token balances that may come from various protocols""" # If we have anything in DSR also count it towards total blockchain balances eth_balances = self.balances.eth dsr_module = self.makerdao_dsr if dsr_module is not None: additional_total = Balance() current_dsr_report = dsr_module.get_current_dsr() for dsr_account, balance_entry in current_dsr_report.balances.items(): if balance_entry.amount == ZERO: continue eth_balances[dsr_account].assets[A_DAI] += balance_entry additional_total += balance_entry if additional_total.amount != ZERO: self.totals.assets[A_DAI] += additional_total # Also count the vault balance and defi saver wallets and add it to the totals vaults_module = self.makerdao_vaults if vaults_module is not None: balances = vaults_module.get_balances() for address, entry in balances.items(): if address not in eth_balances: self.msg_aggregator.add_error( f'The owner of a vault {address} was not in the tracked addresses.' f' This should not happen and is probably a bug. Please report it.', ) else: eth_balances[address] += entry self.totals += entry proxy_mappings = vaults_module._get_accounts_having_maker_proxy() proxy_to_address = {} proxy_addresses = [] for user_address, proxy_address in proxy_mappings.items(): proxy_to_address[proxy_address] = user_address proxy_addresses.append(proxy_address) ethtokens = EthTokens(database=self.database, ethereum=self.ethereum) try: balance_result, token_usd_price = ethtokens.query_tokens_for_addresses( addresses=proxy_addresses, force_detection=False, ) except BadFunctionCallOutput as e: log.error( 'Assuming unsynced chain. Got web3 BadFunctionCallOutput ' 'exception: {}'.format(str(e)), ) raise EthSyncError( 'Tried to use the ethereum chain of the provided client to query ' 'token balances but the chain is not synced.', ) from e new_result = {proxy_to_address[x]: v for x, v in balance_result.items()} self._update_balances_after_token_query( action=AccountAction.DSR_PROXY_APPEND, balance_result=new_result, token_usd_price=token_usd_price, ) # also query defi balances to get liabilities defi_balances_map = self.defichad.query_defi_balances(proxy_addresses) for proxy_address, defi_balances in defi_balances_map.items(): self._add_account_defi_balances_to_token_and_totals( account=proxy_to_address[proxy_address], balances=defi_balances, ) adex_module = self.adex if adex_module is not None and self.premium is not None: adex_balances = adex_module.get_balances(addresses=self.accounts.eth) for address, pool_balances in adex_balances.items(): for pool_balance in pool_balances: eth_balances[address].assets[A_ADX] += pool_balance.adx_balance self.totals.assets[A_ADX] += pool_balance.adx_balance eth_balances[address].assets[A_DAI] += pool_balance.dai_unclaimed_balance self.totals.assets[A_DAI] += pool_balance.dai_unclaimed_balance # Count ETH staked in Eth2 beacon chain self.account_for_staked_eth2_balances(addresses=self.accounts.eth, at_addition=False) # Finally count the balances detected in various protocols in defi balances self.add_defi_balances_to_token_and_totals()