def asset_normalized_value(amount: int, asset: Asset) -> FVal: """Takes in an amount and an asset and returns its normalized value May raise: - UnsupportedAsset if the given asset is not ETH or an ethereum token """ if asset.identifier == 'ETH': decimals = 18 else: if not asset.is_eth_token(): raise UnsupportedAsset(asset.identifier) decimals = EthereumToken(asset.identifier).decimals return token_normalized_value_decimals(amount, decimals)
def get_asset_balance_total(asset: Asset, setup: BalancesTestSetup) -> FVal: conversion_function = satoshis_to_btc if asset == A_BTC else from_wei total = ZERO if asset in (A_ETH, A_BTC): asset_balances = getattr(setup, f'{asset.symbol.lower()}_balances') total += sum(conversion_function(FVal(b)) for b in asset_balances) elif asset.is_eth_token(): asset_balances = setup.token_balances[asset] # type: ignore total += sum(conversion_function(FVal(b)) for b in asset_balances) total += setup.binance_balances.get(asset, ZERO) total += setup.poloniex_balances.get(asset, ZERO) if setup.manually_tracked_balances: for entry in setup.manually_tracked_balances: if entry.asset == asset: total += entry.amount return total
def get_asset_balance_total(asset_symbol: str, setup: BalancesTestSetup) -> FVal: conversion_function = satoshis_to_btc if asset_symbol == 'BTC' else from_wei total = ZERO asset = Asset(asset_symbol) if asset_symbol in ('ETH', 'BTC'): asset_balances = getattr(setup, f'{asset_symbol.lower()}_balances') total += sum(conversion_function(FVal(b)) for b in asset_balances) elif asset.is_eth_token(): asset_balances = setup.token_balances[EthereumToken(asset_symbol)] total += sum(conversion_function(FVal(b)) for b in asset_balances) total += setup.binance_balances.get(asset_symbol, ZERO) total += setup.poloniex_balances.get(asset_symbol, ZERO) if setup.manually_tracked_balances: for entry in setup.manually_tracked_balances: if entry.asset.identifier == asset_symbol: total += entry.amount return total
def get_price( self, from_asset: Asset, to_asset: Asset, block_identifier: BlockIdentifier, ) -> Price: """ Return the price of from_asset to to_asset at the block block_identifier. External oracles are used if non eth tokens are used. Can raise: - PriceQueryUnsupportedAsset - RemoteError """ log.debug( f'Searching price for {from_asset} to {to_asset} at ' f'{block_identifier!r} with {self.name}', ) # Uniswap V2 and V3 use in their contracts WETH instead of ETH if from_asset == A_ETH: from_asset = A_WETH if to_asset == A_ETH: to_asset = A_WETH if from_asset == to_asset: return Price(ONE) if not (from_asset.is_eth_token() and to_asset.is_eth_token()): raise PriceQueryUnsupportedAsset( f'Either {from_asset} or {to_asset} arent ethereum tokens for the uniswap oracle', ) # Could be that we are dealing with ethereum tokens as instances of Asset instead of # EthereumToken, handle the conversion from_asset_raw: Union[Asset, EthereumToken] = from_asset to_asset_raw: Union[Asset, EthereumToken] = to_asset if not isinstance(from_asset, EthereumToken): from_as_token = EthereumToken.from_asset(from_asset) if from_as_token is None: raise PriceQueryUnsupportedAsset( f'Unsupported asset for uniswap {from_asset_raw}') from_asset = from_as_token if not isinstance(to_asset, EthereumToken): to_as_token = EthereumToken.from_asset(to_asset) if to_as_token is None: raise PriceQueryUnsupportedAsset( f'Unsupported asset for uniswap {to_asset_raw}') to_asset = to_as_token route = self.find_route(from_asset, to_asset) if len(route) == 0: log.debug( f'Failed to find uniswap price for {from_asset} to {to_asset}') return Price(ZERO) log.debug( f'Found price route {route} for {from_asset} to {to_asset} using {self.name}' ) prices_and_tokens = [] for step in route: log.debug(f'Getting pool price for {step}') prices_and_tokens.append( self.get_pool_price( pool_addr=to_checksum_address(step), block_identifier=block_identifier, ), ) # Looking at which one is token0 and token1 we need to see if we need price or 1/price if prices_and_tokens[0].token_0 != from_asset: prices_and_tokens[0] = prices_and_tokens[0].swap_tokens() # For the possible intermediate steps also make sure that we use the correct price for pos, item in enumerate(prices_and_tokens[1:-1]): if item.token_0 != prices_and_tokens[pos - 1].token_1: prices_and_tokens[pos - 1] = prices_and_tokens[pos - 1].swap_tokens() # Finally for the tail query the price if prices_and_tokens[-1].token_1 != to_asset: prices_and_tokens[-1] = prices_and_tokens[-1].swap_tokens() price = FVal(reduce(mul, [item.price for item in prices_and_tokens], 1)) return Price(price)