Esempio n. 1
0
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)
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
    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)