Handle missing price (show 0)
This commit is contained in:
		
							parent
							
								
									b6532d8cf4
								
							
						
					
					
						commit
						adf9c12eb5
					
				@ -1,8 +1,8 @@
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import * as WebSocket from 'ws';
 | 
			
		||||
import {
 | 
			
		||||
  BlockExtended, TransactionExtended, WebsocketResponse, MempoolBlock, MempoolBlockDelta,
 | 
			
		||||
  OptimizedStatistic, ILoadingIndicators, IConversionRates
 | 
			
		||||
  BlockExtended, TransactionExtended, WebsocketResponse,
 | 
			
		||||
  OptimizedStatistic, ILoadingIndicators
 | 
			
		||||
} from '../mempool.interfaces';
 | 
			
		||||
import blocks from './blocks';
 | 
			
		||||
import memPool from './mempool';
 | 
			
		||||
@ -20,6 +20,7 @@ import BlocksSummariesRepository from '../repositories/BlocksSummariesRepository
 | 
			
		||||
import Audit from './audit';
 | 
			
		||||
import { deepClone } from '../utils/clone';
 | 
			
		||||
import priceUpdater from '../tasks/price-updater';
 | 
			
		||||
import { ApiPrice } from '../repositories/PricesRepository';
 | 
			
		||||
 | 
			
		||||
class WebsocketHandler {
 | 
			
		||||
  private wss: WebSocket.Server | undefined;
 | 
			
		||||
@ -193,7 +194,7 @@ class WebsocketHandler {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleNewConversionRates(conversionRates: IConversionRates) {
 | 
			
		||||
  handleNewConversionRates(conversionRates: ApiPrice) {
 | 
			
		||||
    if (!this.wss) {
 | 
			
		||||
      throw new Error('WebSocket.Server is not set');
 | 
			
		||||
    }
 | 
			
		||||
@ -214,7 +215,7 @@ class WebsocketHandler {
 | 
			
		||||
      'mempoolInfo': memPool.getMempoolInfo(),
 | 
			
		||||
      'vBytesPerSecond': memPool.getVBytesPerSecond(),
 | 
			
		||||
      'blocks': _blocks,
 | 
			
		||||
      'conversions': priceUpdater.latestPrices,
 | 
			
		||||
      'conversions': priceUpdater.getLatestPrices(),
 | 
			
		||||
      'mempool-blocks': mempoolBlocks.getMempoolBlocks(),
 | 
			
		||||
      'transactions': memPool.getLatestTransactions(),
 | 
			
		||||
      'backendInfo': backendInfo.getBackendInfo(),
 | 
			
		||||
 | 
			
		||||
@ -293,7 +293,6 @@ interface RequiredParams {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ILoadingIndicators { [name: string]: number; }
 | 
			
		||||
export interface IConversionRates { [currency: string]: number; }
 | 
			
		||||
 | 
			
		||||
export interface IBackendInfo {
 | 
			
		||||
  hostname: string;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import DB from '../database';
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import { IConversionRates } from '../mempool.interfaces';
 | 
			
		||||
import priceUpdater from '../tasks/price-updater';
 | 
			
		||||
 | 
			
		||||
export interface ApiPrice {
 | 
			
		||||
@ -13,6 +12,16 @@ export interface ApiPrice {
 | 
			
		||||
  AUD: number,
 | 
			
		||||
  JPY: number,
 | 
			
		||||
}
 | 
			
		||||
const ApiPriceFields = `
 | 
			
		||||
  UNIX_TIMESTAMP(time) as time,
 | 
			
		||||
  USD,
 | 
			
		||||
  EUR,
 | 
			
		||||
  GBP,
 | 
			
		||||
  CAD,
 | 
			
		||||
  CHF,
 | 
			
		||||
  AUD,
 | 
			
		||||
  JPY
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
export interface ExchangeRates {
 | 
			
		||||
  USDEUR: number,
 | 
			
		||||
@ -39,7 +48,7 @@ export const MAX_PRICES = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class PricesRepository {
 | 
			
		||||
  public async $savePrices(time: number, prices: IConversionRates): Promise<void> {
 | 
			
		||||
  public async $savePrices(time: number, prices: ApiPrice): Promise<void> {
 | 
			
		||||
    if (prices.USD === -1) {
 | 
			
		||||
      // Some historical price entries have no USD prices, so we just ignore them to avoid future UX issues
 | 
			
		||||
      // As of today there are only 4 (on 2013-09-05, 2013-0909, 2013-09-12 and 2013-09-26) so that's fine
 | 
			
		||||
@ -60,77 +69,115 @@ class PricesRepository {
 | 
			
		||||
        VALUE             (FROM_UNIXTIME(?), ?,   ?,   ?,   ?,   ?,   ?,   ?  )`,
 | 
			
		||||
        [time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY]
 | 
			
		||||
      );
 | 
			
		||||
    } catch (e: any) {
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      logger.err(`Cannot save exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e));
 | 
			
		||||
      throw e;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getOldestPriceTime(): Promise<number> {
 | 
			
		||||
    const [oldestRow] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time LIMIT 1`);
 | 
			
		||||
    const [oldestRow] = await DB.query(`
 | 
			
		||||
      SELECT UNIX_TIMESTAMP(time) AS time
 | 
			
		||||
      FROM prices
 | 
			
		||||
      ORDER BY time
 | 
			
		||||
      LIMIT 1
 | 
			
		||||
    `);
 | 
			
		||||
    return oldestRow[0] ? oldestRow[0].time : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestPriceId(): Promise<number | null> {
 | 
			
		||||
    const [oldestRow] = await DB.query(`SELECT id from prices WHERE USD != 0 ORDER BY time DESC LIMIT 1`);
 | 
			
		||||
    return oldestRow[0] ? oldestRow[0].id : null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestPriceTime(): Promise<number> {
 | 
			
		||||
    const [oldestRow] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time DESC LIMIT 1`);
 | 
			
		||||
    return oldestRow[0] ? oldestRow[0].time : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getPricesTimes(): Promise<number[]> {
 | 
			
		||||
    const [times]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time from prices WHERE USD != 0 ORDER BY time`);
 | 
			
		||||
    return times.map(time => time.time);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getPricesTimesAndId(): Promise<number[]> {
 | 
			
		||||
    const [times]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(time) as time, id, USD from prices ORDER BY time`);
 | 
			
		||||
    return times;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestConversionRates(): Promise<any> {
 | 
			
		||||
    const [rates]: any[] = await DB.query(`
 | 
			
		||||
      SELECT USD, EUR, GBP, CAD, CHF, AUD, JPY
 | 
			
		||||
    const [oldestRow] = await DB.query(`
 | 
			
		||||
      SELECT id
 | 
			
		||||
      FROM prices
 | 
			
		||||
      ORDER BY time DESC
 | 
			
		||||
      LIMIT 1`
 | 
			
		||||
    );
 | 
			
		||||
    if (!rates || rates.length === 0) {
 | 
			
		||||
    return oldestRow[0] ? oldestRow[0].id : null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestPriceTime(): Promise<number> {
 | 
			
		||||
    const [oldestRow] = await DB.query(`
 | 
			
		||||
      SELECT UNIX_TIMESTAMP(time) AS time
 | 
			
		||||
      FROM prices
 | 
			
		||||
      ORDER BY time DESC
 | 
			
		||||
      LIMIT 1`
 | 
			
		||||
    );
 | 
			
		||||
    return oldestRow[0] ? oldestRow[0].time : 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getPricesTimes(): Promise<number[]> {
 | 
			
		||||
    const [times] = await DB.query(`
 | 
			
		||||
      SELECT UNIX_TIMESTAMP(time) AS time
 | 
			
		||||
      FROM prices
 | 
			
		||||
      WHERE USD != -1
 | 
			
		||||
      ORDER BY time
 | 
			
		||||
    `);
 | 
			
		||||
    if (!Array.isArray(times)) {
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
    return times.map(time => time.time);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getPricesTimesAndId(): Promise<{time: number, id: number, USD: number}[]> {
 | 
			
		||||
    const [times] = await DB.query(`
 | 
			
		||||
      SELECT
 | 
			
		||||
        UNIX_TIMESTAMP(time) AS time,
 | 
			
		||||
        id,
 | 
			
		||||
        USD
 | 
			
		||||
      FROM prices
 | 
			
		||||
      ORDER BY time
 | 
			
		||||
    `);
 | 
			
		||||
    return times as {time: number, id: number, USD: number}[];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestConversionRates(): Promise<ApiPrice> {
 | 
			
		||||
    const [rates] = await DB.query(`
 | 
			
		||||
      SELECT ${ApiPriceFields}
 | 
			
		||||
      FROM prices
 | 
			
		||||
      ORDER BY time DESC
 | 
			
		||||
      LIMIT 1`
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!Array.isArray(rates) || rates.length === 0) {
 | 
			
		||||
      return priceUpdater.getEmptyPricesObj();
 | 
			
		||||
    }
 | 
			
		||||
    return rates[0];
 | 
			
		||||
    return rates[0] as ApiPrice;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getNearestHistoricalPrice(timestamp: number | undefined): Promise<Conversion | null> {
 | 
			
		||||
    try {
 | 
			
		||||
      const [rates]: any[] = await DB.query(`
 | 
			
		||||
        SELECT *, UNIX_TIMESTAMP(time) AS time
 | 
			
		||||
      const [rates] = await DB.query(`
 | 
			
		||||
        SELECT ${ApiPriceFields}
 | 
			
		||||
        FROM prices
 | 
			
		||||
        WHERE UNIX_TIMESTAMP(time) < ?
 | 
			
		||||
        ORDER BY time DESC
 | 
			
		||||
        LIMIT 1`,
 | 
			
		||||
        [timestamp]
 | 
			
		||||
      );
 | 
			
		||||
      if (!rates) {
 | 
			
		||||
      if (!Array.isArray(rates)) {
 | 
			
		||||
        throw Error(`Cannot get single historical price from the database`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Compute fiat exchange rates
 | 
			
		||||
      const latestPrice = await this.$getLatestConversionRates();
 | 
			
		||||
      let latestPrice = rates[0] as ApiPrice;
 | 
			
		||||
      if (latestPrice.USD === -1) {
 | 
			
		||||
        latestPrice = priceUpdater.getEmptyPricesObj();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const computeFx = (usd: number, other: number): number =>
 | 
			
		||||
        Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
 | 
			
		||||
      
 | 
			
		||||
      const exchangeRates: ExchangeRates = {
 | 
			
		||||
        USDEUR: Math.round(latestPrice.EUR / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDGBP: Math.round(latestPrice.GBP / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDCAD: Math.round(latestPrice.CAD / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDCHF: Math.round(latestPrice.CHF / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDAUD: Math.round(latestPrice.AUD / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDJPY: Math.round(latestPrice.JPY / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
 | 
			
		||||
        USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
 | 
			
		||||
        USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
 | 
			
		||||
        USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
 | 
			
		||||
        USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
 | 
			
		||||
        USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        prices: rates,
 | 
			
		||||
        prices: rates as ApiPrice[],
 | 
			
		||||
        exchangeRates: exchangeRates
 | 
			
		||||
      };
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@ -141,28 +188,35 @@ class PricesRepository {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalPrices(): Promise<Conversion | null> {
 | 
			
		||||
    try {
 | 
			
		||||
      const [rates]: any[] = await DB.query(`
 | 
			
		||||
        SELECT *, UNIX_TIMESTAMP(time) AS time
 | 
			
		||||
      const [rates] = await DB.query(`
 | 
			
		||||
        SELECT ${ApiPriceFields}
 | 
			
		||||
        FROM prices
 | 
			
		||||
        ORDER BY time DESC
 | 
			
		||||
      `);
 | 
			
		||||
      if (!rates) {
 | 
			
		||||
      if (!Array.isArray(rates)) {
 | 
			
		||||
        throw Error(`Cannot get average historical price from the database`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Compute fiat exchange rates
 | 
			
		||||
      const latestPrice: ApiPrice = rates[0];
 | 
			
		||||
      let latestPrice = rates[0] as ApiPrice;
 | 
			
		||||
      if (latestPrice.USD === -1) {
 | 
			
		||||
        latestPrice = priceUpdater.getEmptyPricesObj();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const computeFx = (usd: number, other: number): number =>
 | 
			
		||||
        Math.round(Math.max(other, 0) / Math.max(usd, 1) * 100) / 100;
 | 
			
		||||
      
 | 
			
		||||
      const exchangeRates: ExchangeRates = {
 | 
			
		||||
        USDEUR: Math.round(latestPrice.EUR / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDGBP: Math.round(latestPrice.GBP / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDCAD: Math.round(latestPrice.CAD / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDCHF: Math.round(latestPrice.CHF / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDAUD: Math.round(latestPrice.AUD / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDJPY: Math.round(latestPrice.JPY / latestPrice.USD * 100) / 100,
 | 
			
		||||
        USDEUR: computeFx(latestPrice.USD, latestPrice.EUR),
 | 
			
		||||
        USDGBP: computeFx(latestPrice.USD, latestPrice.GBP),
 | 
			
		||||
        USDCAD: computeFx(latestPrice.USD, latestPrice.CAD),
 | 
			
		||||
        USDCHF: computeFx(latestPrice.USD, latestPrice.CHF),
 | 
			
		||||
        USDAUD: computeFx(latestPrice.USD, latestPrice.AUD),
 | 
			
		||||
        USDJPY: computeFx(latestPrice.USD, latestPrice.JPY),
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        prices: rates,
 | 
			
		||||
        prices: rates as ApiPrice[],
 | 
			
		||||
        exchangeRates: exchangeRates
 | 
			
		||||
      };
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
 | 
			
		||||
@ -8,9 +8,6 @@ class BitfinexApi implements PriceFeed {
 | 
			
		||||
  public url: string = 'https://api.bitfinex.com/v1/pubticker/BTC';
 | 
			
		||||
  public urlHist: string = 'https://api-pub.bitfinex.com/v2/candles/trade:{GRANULARITY}:tBTC{CURRENCY}/hist';
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $fetchPrice(currency): Promise<number> {
 | 
			
		||||
    const response = await query(this.url + currency);
 | 
			
		||||
    if (response && response['last_price']) {
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,7 @@ import * as fs from 'fs';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import config from '../config';
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import { IConversionRates } from '../mempool.interfaces';
 | 
			
		||||
import PricesRepository, { MAX_PRICES } from '../repositories/PricesRepository';
 | 
			
		||||
import PricesRepository, { ApiPrice, MAX_PRICES } from '../repositories/PricesRepository';
 | 
			
		||||
import BitfinexApi from './price-feeds/bitfinex-api';
 | 
			
		||||
import BitflyerApi from './price-feeds/bitflyer-api';
 | 
			
		||||
import CoinbaseApi from './price-feeds/coinbase-api';
 | 
			
		||||
@ -21,18 +20,18 @@ export interface PriceFeed {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PriceHistory {
 | 
			
		||||
  [timestamp: number]: IConversionRates;
 | 
			
		||||
  [timestamp: number]: ApiPrice;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PriceUpdater {
 | 
			
		||||
  public historyInserted = false;
 | 
			
		||||
  lastRun = 0;
 | 
			
		||||
  lastHistoricalRun = 0;
 | 
			
		||||
  running = false;
 | 
			
		||||
  feeds: PriceFeed[] = [];
 | 
			
		||||
  currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY'];
 | 
			
		||||
  latestPrices: IConversionRates;
 | 
			
		||||
  private ratesChangedCallback: ((rates: IConversionRates) => void) | undefined;
 | 
			
		||||
  private lastRun = 0;
 | 
			
		||||
  private lastHistoricalRun = 0;
 | 
			
		||||
  private running = false;
 | 
			
		||||
  private feeds: PriceFeed[] = [];
 | 
			
		||||
  private currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY'];
 | 
			
		||||
  private latestPrices: ApiPrice;
 | 
			
		||||
  private ratesChangedCallback: ((rates: ApiPrice) => void) | undefined;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.latestPrices = this.getEmptyPricesObj();
 | 
			
		||||
@ -44,8 +43,13 @@ class PriceUpdater {
 | 
			
		||||
    this.feeds.push(new GeminiApi());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getEmptyPricesObj(): IConversionRates {
 | 
			
		||||
  public getLatestPrices(): ApiPrice {
 | 
			
		||||
    return this.latestPrices;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getEmptyPricesObj(): ApiPrice {
 | 
			
		||||
    return {
 | 
			
		||||
      time: 0,
 | 
			
		||||
      USD: -1,
 | 
			
		||||
      EUR: -1,
 | 
			
		||||
      GBP: -1,
 | 
			
		||||
@ -56,7 +60,7 @@ class PriceUpdater {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public setRatesChangedCallback(fn: (rates: IConversionRates) => void) {
 | 
			
		||||
  public setRatesChangedCallback(fn: (rates: ApiPrice) => void): void {
 | 
			
		||||
    this.ratesChangedCallback = fn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -156,6 +160,10 @@ class PriceUpdater {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.lastRun = new Date().getTime() / 1000;
 | 
			
		||||
 | 
			
		||||
    if (this.latestPrices.USD === -1) {
 | 
			
		||||
      this.latestPrices = await PricesRepository.$getLatestConversionRates();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -224,7 +232,7 @@ class PriceUpdater {
 | 
			
		||||
 | 
			
		||||
    // Group them by timestamp and currency, for example
 | 
			
		||||
    // grouped[123456789]['USD'] = [1, 2, 3, 4];
 | 
			
		||||
    const grouped: any = {};
 | 
			
		||||
    const grouped = {};
 | 
			
		||||
    for (const historicalEntry of historicalPrices) {
 | 
			
		||||
      for (const time in historicalEntry) {
 | 
			
		||||
        if (existingPriceTimes.includes(parseInt(time, 10))) {
 | 
			
		||||
@ -249,7 +257,7 @@ class PriceUpdater {
 | 
			
		||||
    // Average prices and insert everything into the db
 | 
			
		||||
    let totalInserted = 0;
 | 
			
		||||
    for (const time in grouped) {
 | 
			
		||||
      const prices: IConversionRates = this.getEmptyPricesObj();
 | 
			
		||||
      const prices: ApiPrice = this.getEmptyPricesObj();
 | 
			
		||||
      for (const currency in grouped[time]) {
 | 
			
		||||
        if (grouped[time][currency].length === 0) {
 | 
			
		||||
          continue;
 | 
			
		||||
 | 
			
		||||
@ -3,13 +3,15 @@
 | 
			
		||||
    {{ addPlus && satoshis >= 0 ? '+' : '' }}
 | 
			
		||||
    {{
 | 
			
		||||
      (
 | 
			
		||||
        (blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
 | 
			
		||||
        (blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
 | 
			
		||||
        (blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
 | 
			
		||||
        (blockConversion.price['USD']    > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
 | 
			
		||||
      ) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency
 | 
			
		||||
    }}
 | 
			
		||||
  </span>
 | 
			
		||||
  <ng-template #noblockconversion>
 | 
			
		||||
    <span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ (conversions ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}</span>
 | 
			
		||||
    <span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}
 | 
			
		||||
      {{ (conversions[currency] > -1 ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}
 | 
			
		||||
    </span>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</ng-container>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,14 @@
 | 
			
		||||
<span class="green-color" *ngIf="blockConversion; else noblockconversion">
 | 
			
		||||
  {{
 | 
			
		||||
    (
 | 
			
		||||
      (blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
 | 
			
		||||
      (blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
 | 
			
		||||
      (blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
 | 
			
		||||
      (blockConversion.price['USD']    > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
 | 
			
		||||
    ) * value / 100000000 | fiatCurrency : digitsInfo : currency
 | 
			
		||||
  }}
 | 
			
		||||
</span>
 | 
			
		||||
 | 
			
		||||
<ng-template #noblockconversion>
 | 
			
		||||
  <span class="green-color" *ngIf="(conversions$ | async) as conversions">
 | 
			
		||||
    {{ (conversions[currency] ?? conversions['USD'] ?? 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
 | 
			
		||||
    {{ (conversions[currency] > -1 ? conversions[currency] : 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
 | 
			
		||||
  </span>
 | 
			
		||||
</ng-template>
 | 
			
		||||
@ -89,7 +89,7 @@ export class PriceService {
 | 
			
		||||
      return this.singlePriceObservable$.pipe(
 | 
			
		||||
        map((conversion) => {
 | 
			
		||||
          if (conversion.prices.length <= 0) {
 | 
			
		||||
            return this.getEmptyPrice();
 | 
			
		||||
            return undefined;
 | 
			
		||||
          }
 | 
			
		||||
          return {
 | 
			
		||||
            price: {
 | 
			
		||||
@ -113,7 +113,7 @@ export class PriceService {
 | 
			
		||||
 | 
			
		||||
      return this.priceObservable$.pipe(
 | 
			
		||||
        map((conversion) => {
 | 
			
		||||
          if (!blockTimestamp) {
 | 
			
		||||
          if (!blockTimestamp || !conversion) {
 | 
			
		||||
            return undefined;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user