def _handle_pooltogether(normalized_balance: FVal, token_name: str) -> Optional[DefiBalance]: """Special handling for pooltogether https://github.com/rotki/rotki/issues/1429 """ if 'DAI' in token_name: dai_price = Inquirer.find_usd_price(A_DAI) return DefiBalance( token_address=to_checksum_address( '0x49d716DFe60b37379010A75329ae09428f17118d'), token_name='Pool Together DAI token', token_symbol='plDAI', balance=Balance( amount=normalized_balance, usd_value=normalized_balance * dai_price, ), ) if 'USDC' in token_name: usdc_price = Inquirer.find_usd_price(A_USDC) return DefiBalance( token_address=to_checksum_address( '0xBD87447F48ad729C5c4b8bcb503e1395F62e8B98'), token_name='Pool Together USDC token', token_symbol='plUSDC', balance=Balance( amount=normalized_balance, usd_value=normalized_balance * usdc_price, ), ) # else return None
def handle_protocols( self, protocol_name: str, token_symbol: str, normalized_balance: FVal, token_address: str, token_name: str, ) -> Optional[DefiBalance]: """Special handling for price for token/protocols which are easier to do onchain or need some kind of special treatment. """ if protocol_name == 'PoolTogether': result = _handle_pooltogether(normalized_balance, token_name) if result is not None: return result underlying_asset_price = get_underlying_asset_price(token_symbol) usd_price = handle_defi_price_query(self.ethereum, token_symbol, underlying_asset_price) if usd_price is None: return None return DefiBalance( token_address=to_checksum_address(token_address), token_name=token_name, token_symbol=token_symbol, balance=Balance(amount=normalized_balance, usd_value=normalized_balance * usd_price), )
def mock_query_defi_balances(): blockchain.defi_balances = { addr1: [DefiProtocolBalances( protocol=DefiProtocol('a', 'b', 'c', 1), balance_type='Asset', base_balance=DefiBalance( token_address=A_DAI.ethereum_address, token_name='DAI', token_symbol='DAI', balance=Balance(amount=FVal(1), usd_value=(1)), ), underlying_balances=[DefiBalance( token_address=A_DAI.ethereum_address, token_name='DAI', token_symbol='DAI', balance=Balance(amount=FVal(1), usd_value=(1)), )], )], } return blockchain.defi_balances
def query_defi_balances( self, addresses: List[ChecksumEthAddress], ) -> Dict[ChecksumEthAddress, List[DefiProtocolBalances]]: defi_balances = defaultdict(list) for account in addresses: balances = self.zerion_sdk.all_balances_for_account(account) if len(balances) != 0: defi_balances[account] = balances # and also query balances of tokens that are not detected by zerion adapter contract result = multicall_specific( ethereum=self.ethereum, contract=VOTE_ESCROWED_CRV, method_name='locked', arguments=[[x] for x in addresses], ) crv_price = Price(ZERO) if any(x[0] != 0 for x in result): crv_price = Inquirer().find_usd_price(A_CRV) for idx, address in enumerate(addresses): balance = result[idx][0] if balance == 0: continue # else the address has vote escrowed CRV amount = token_normalized_value_decimals(token_amount=balance, token_decimals=18) protocol_balance = DefiProtocolBalances( protocol=DefiProtocol( name='Curve • Vesting', description='Curve vesting or locked in escrow for voting', url='https://www.curve.fi/', version=1, ), balance_type='Asset', base_balance=DefiBalance( token_address=VOTE_ESCROWED_CRV.address, token_name='Vote-escrowed CRV', token_symbol='veCRV', balance=Balance( amount=amount, usd_value=amount * crv_price, ), ), underlying_balances=[], ) defi_balances[address].append(protocol_balance) return defi_balances
def _get_single_balance( self, protocol_name: str, entry: Tuple[Tuple[str, str, str, int], int], ) -> DefiBalance: """ This method can raise DeserializationError while deserializing the token address or handling the specific protocol. """ metadata = entry[0] balance_value = entry[1] decimals = metadata[3] normalized_value = token_normalized_value_decimals( balance_value, decimals) token_symbol = metadata[2] token_address = deserialize_ethereum_address(metadata[0]) token_name = metadata[1] special_handling = self.handle_protocols( protocol_name=protocol_name, token_symbol=token_symbol, normalized_balance=normalized_value, token_address=token_address, token_name=token_name, ) if special_handling: return special_handling try: token = EthereumToken(token_address) usd_price = Inquirer().find_usd_price(token) except (UnknownAsset, UnsupportedAsset): if not _is_token_non_standard(token_symbol, token_address): self.msg_aggregator.add_warning( f'Unsupported asset {token_symbol} with address ' f'{token_address} encountered during DeFi protocol queries', ) usd_price = Price(ZERO) usd_value = normalized_value * usd_price defi_balance = DefiBalance( token_address=token_address, token_name=token_name, token_symbol=token_symbol, balance=Balance(amount=normalized_value, usd_value=usd_value), ) return defi_balance
def handle_protocols( self, protocol_name: str, token_symbol: str, normalized_balance: FVal, token_address: str, token_name: str, ) -> Optional[DefiBalance]: """Special handling for price for token/protocols which are easier to do onchain or need some kind of special treatment. This method can raise DeserializationError """ if protocol_name == 'PoolTogether': result = _handle_pooltogether(normalized_balance, token_name) if result is not None: return result asset = get_asset_by_symbol(token_symbol) if asset is None: return None token = EthereumToken.from_asset(asset) if token is None: return None underlying_asset_price = get_underlying_asset_price(token) usd_price = handle_defi_price_query(self.ethereum, token, underlying_asset_price) if usd_price is None: return None return DefiBalance( token_address=deserialize_ethereum_address(token_address), token_name=token_name, token_symbol=token_symbol, balance=Balance(amount=normalized_balance, usd_value=normalized_balance * usd_price), )