Merge branch 'master' into mononaut/sliding-difficulty
This commit is contained in:
		
						commit
						5f14b32a06
					
				@ -398,39 +398,24 @@ class ElementsParser {
 | 
				
			|||||||
    return rows;
 | 
					    return rows;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Get all of the federation addresses one month ago, most balances first
 | 
					  // Get the total number of federation addresses
 | 
				
			||||||
  public async $getFederationAddressesOneMonthAgo(): Promise<any> {
 | 
					  public async $getFederationAddressesNumber(): Promise<any> {
 | 
				
			||||||
    const query = `
 | 
					    const query = `SELECT COUNT(DISTINCT bitcoinaddress) AS address_count FROM federation_txos WHERE unspent = 1;`;
 | 
				
			||||||
    SELECT COUNT(*) AS addresses_count_one_month FROM (
 | 
					 | 
				
			||||||
      SELECT bitcoinaddress, SUM(amount) AS balance
 | 
					 | 
				
			||||||
      FROM federation_txos 
 | 
					 | 
				
			||||||
      WHERE
 | 
					 | 
				
			||||||
          (blocktime < UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -30, CURRENT_TIMESTAMP())))
 | 
					 | 
				
			||||||
        AND
 | 
					 | 
				
			||||||
          ((unspent = 1) OR (unspent = 0 AND lasttimeupdate > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -30, CURRENT_TIMESTAMP()))))
 | 
					 | 
				
			||||||
      GROUP BY bitcoinaddress
 | 
					 | 
				
			||||||
    ) AS result;`;
 | 
					 | 
				
			||||||
    const [rows] = await DB.query(query);
 | 
					    const [rows] = await DB.query(query);
 | 
				
			||||||
    return rows[0];
 | 
					    return rows[0];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Get all of the UTXOs held by the federation one month ago, most recent first
 | 
					  // Get the total number of federation utxos
 | 
				
			||||||
  public async $getFederationUtxosOneMonthAgo(): Promise<any> {
 | 
					  public async $getFederationUtxosNumber(): Promise<any> {
 | 
				
			||||||
    const query = `
 | 
					    const query = `SELECT COUNT(*) AS utxo_count FROM federation_txos WHERE unspent = 1;`;
 | 
				
			||||||
    SELECT COUNT(*) AS utxos_count_one_month FROM federation_txos 
 | 
					 | 
				
			||||||
    WHERE
 | 
					 | 
				
			||||||
        (blocktime < UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -30, CURRENT_TIMESTAMP())))
 | 
					 | 
				
			||||||
      AND
 | 
					 | 
				
			||||||
        ((unspent = 1) OR (unspent = 0 AND lasttimeupdate > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -30, CURRENT_TIMESTAMP()))))
 | 
					 | 
				
			||||||
    ORDER BY blocktime DESC;`;
 | 
					 | 
				
			||||||
    const [rows] = await DB.query(query);
 | 
					    const [rows] = await DB.query(query);
 | 
				
			||||||
    return rows[0];
 | 
					    return rows[0];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Get recent pegouts from the federation (3 months old)
 | 
					  // Get recent pegs in / out
 | 
				
			||||||
  public async $getRecentPegouts(): Promise<any> {
 | 
					  public async $getPegsList(count: number = 0): Promise<any> {
 | 
				
			||||||
    const query = `SELECT txid, txindex, amount, bitcoinaddress, bitcointxid, bitcoinindex, datetime AS blocktime FROM elements_pegs WHERE amount < 0 AND datetime > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -90, CURRENT_TIMESTAMP())) ORDER BY blocktime;`;
 | 
					    const query = `SELECT txid, txindex, amount, bitcoinaddress, bitcointxid, bitcoinindex, datetime AS blocktime FROM elements_pegs ORDER BY block DESC LIMIT 15 OFFSET ?;`;
 | 
				
			||||||
    const [rows] = await DB.query(query);
 | 
					    const [rows] = await DB.query(query, [count]);
 | 
				
			||||||
    return rows;
 | 
					    return rows;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -443,6 +428,12 @@ class ElementsParser {
 | 
				
			|||||||
      pegOutQuery[0][0]
 | 
					      pegOutQuery[0][0]
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Get the total pegs number
 | 
				
			||||||
 | 
					  public async $getPegsCount(): Promise<any> {
 | 
				
			||||||
 | 
					    const [rows] = await DB.query(`SELECT COUNT(*) AS pegs_count FROM elements_pegs;`);
 | 
				
			||||||
 | 
					    return rows[0];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new ElementsParser();
 | 
					export default new ElementsParser();
 | 
				
			||||||
 | 
				
			|||||||
@ -17,14 +17,15 @@ class LiquidRoutes {
 | 
				
			|||||||
      app
 | 
					      app
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs', this.$getElementsPegs)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs', this.$getElementsPegs)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', this.$getElementsPegsByMonth)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', this.$getElementsPegsByMonth)
 | 
				
			||||||
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/list/:count', this.$getPegsList)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/volume', this.$getPegsVolumeDaily)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/volume', this.$getPegsVolumeDaily)
 | 
				
			||||||
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/count', this.$getPegsCount)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves', this.$getFederationReserves)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves', this.$getFederationReserves)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/month', this.$getFederationReservesByMonth)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/month', this.$getFederationReservesByMonth)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegouts', this.$getPegOuts)
 | 
					 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses', this.$getFederationAddresses)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses', this.$getFederationAddresses)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses/previous-month', this.$getFederationAddressesOneMonthAgo)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses/total', this.$getFederationAddressesNumber)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos', this.$getFederationUtxos)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos', this.$getFederationUtxos)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/previous-month', this.$getFederationUtxosOneMonthAgo)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/total', this.$getFederationUtxosNumber)
 | 
				
			||||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/status', this.$getFederationAuditStatus)
 | 
					        .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/status', this.$getFederationAuditStatus)
 | 
				
			||||||
        ;
 | 
					        ;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -142,12 +143,12 @@ class LiquidRoutes {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async $getFederationAddressesOneMonthAgo(req: Request, res: Response) {
 | 
					  private async $getFederationAddressesNumber(req: Request, res: Response) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const federationAddresses = await elementsParser.$getFederationAddressesOneMonthAgo();
 | 
					      const federationAddresses = await elementsParser.$getFederationAddressesNumber();
 | 
				
			||||||
      res.header('Pragma', 'public');
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
      res.header('Cache-control', 'public');
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
      res.setHeader('Expires', new Date(Date.now() + 1000 * 60 * 60 * 24).toUTCString());
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
				
			||||||
      res.json(federationAddresses);
 | 
					      res.json(federationAddresses);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
@ -166,25 +167,25 @@ class LiquidRoutes {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async $getFederationUtxosOneMonthAgo(req: Request, res: Response) {
 | 
					  private async $getFederationUtxosNumber(req: Request, res: Response) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const federationUtxos = await elementsParser.$getFederationUtxosOneMonthAgo();
 | 
					      const federationUtxos = await elementsParser.$getFederationUtxosNumber();
 | 
				
			||||||
      res.header('Pragma', 'public');
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
      res.header('Cache-control', 'public');
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
      res.setHeader('Expires', new Date(Date.now() + 1000 * 60 * 60 * 24).toUTCString());
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
				
			||||||
      res.json(federationUtxos);
 | 
					      res.json(federationUtxos);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async $getPegOuts(req: Request, res: Response) {
 | 
					  private async $getPegsList(req: Request, res: Response) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const recentPegOuts = await elementsParser.$getRecentPegouts();
 | 
					      const recentPegs = await elementsParser.$getPegsList(parseInt(req.params?.count));
 | 
				
			||||||
      res.header('Pragma', 'public');
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
      res.header('Cache-control', 'public');
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
				
			||||||
      res.json(recentPegOuts);
 | 
					      res.json(recentPegs);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -202,6 +203,18 @@ class LiquidRoutes {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $getPegsCount(req: Request, res: Response) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const pegsCount = await elementsParser.$getPegsCount();
 | 
				
			||||||
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
				
			||||||
 | 
					      res.json(pegsCount);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new LiquidRoutes();
 | 
					export default new LiquidRoutes();
 | 
				
			||||||
 | 
				
			|||||||
@ -285,7 +285,7 @@ class StatisticsApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public async $list2H(): Promise<OptimizedStatistic[]> {
 | 
					  public async $list2H(): Promise<OptimizedStatistic[]> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY statistics.added DESC LIMIT 120`;
 | 
					      const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL 2 HOUR) AND NOW() ORDER BY statistics.added DESC`;
 | 
				
			||||||
      const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout });
 | 
					      const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout });
 | 
				
			||||||
      return this.mapStatisticToOptimizedStatistic(rows as Statistic[]);
 | 
					      return this.mapStatisticToOptimizedStatistic(rows as Statistic[]);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
@ -296,7 +296,7 @@ class StatisticsApi {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public async $list24H(): Promise<OptimizedStatistic[]> {
 | 
					  public async $list24H(): Promise<OptimizedStatistic[]> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY statistics.added DESC LIMIT 1440`;
 | 
					      const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL 24 HOUR) AND NOW() ORDER BY statistics.added DESC`;
 | 
				
			||||||
      const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout });
 | 
					      const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout });
 | 
				
			||||||
      return this.mapStatisticToOptimizedStatistic(rows as Statistic[]);
 | 
					      return this.mapStatisticToOptimizedStatistic(rows as Statistic[]);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import statisticsApi from './statistics-api';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Statistics {
 | 
					class Statistics {
 | 
				
			||||||
  protected intervalTimer: NodeJS.Timer | undefined;
 | 
					  protected intervalTimer: NodeJS.Timer | undefined;
 | 
				
			||||||
 | 
					  protected lastRun: number = 0;
 | 
				
			||||||
  protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined;
 | 
					  protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) {
 | 
					  public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) {
 | 
				
			||||||
@ -23,15 +24,21 @@ class Statistics {
 | 
				
			|||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
      this.runStatistics();
 | 
					      this.runStatistics();
 | 
				
			||||||
      this.intervalTimer = setInterval(() => {
 | 
					      this.intervalTimer = setInterval(() => {
 | 
				
			||||||
        this.runStatistics();
 | 
					        this.runStatistics(true);
 | 
				
			||||||
      }, 1 * 60 * 1000);
 | 
					      }, 1 * 60 * 1000);
 | 
				
			||||||
    }, difference);
 | 
					    }, difference);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async runStatistics(): Promise<void> {
 | 
					  public async runStatistics(skipIfRecent = false): Promise<void> {
 | 
				
			||||||
    if (!memPool.isInSync()) {
 | 
					    if (!memPool.isInSync()) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (skipIfRecent && new Date().getTime() / 1000 - this.lastRun < 30) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.lastRun = new Date().getTime() / 1000;
 | 
				
			||||||
    const currentMempool = memPool.getMempool();
 | 
					    const currentMempool = memPool.getMempool();
 | 
				
			||||||
    const txPerSecond = memPool.getTxPerSecond();
 | 
					    const txPerSecond = memPool.getTxPerSecond();
 | 
				
			||||||
    const vBytesPerSecond = memPool.getVBytesPerSecond();
 | 
					    const vBytesPerSecond = memPool.getVBytesPerSecond();
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ import priceUpdater from '../tasks/price-updater';
 | 
				
			|||||||
import { ApiPrice } from '../repositories/PricesRepository';
 | 
					import { ApiPrice } from '../repositories/PricesRepository';
 | 
				
			||||||
import accelerationApi from './services/acceleration';
 | 
					import accelerationApi from './services/acceleration';
 | 
				
			||||||
import mempool from './mempool';
 | 
					import mempool from './mempool';
 | 
				
			||||||
 | 
					import statistics from './statistics/statistics';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface AddressTransactions {
 | 
					interface AddressTransactions {
 | 
				
			||||||
  mempool: MempoolTransactionExtended[],
 | 
					  mempool: MempoolTransactionExtended[],
 | 
				
			||||||
@ -723,6 +724,7 @@ class WebsocketHandler {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.printLogs();
 | 
					    this.printLogs();
 | 
				
			||||||
 | 
					    await statistics.runStatistics();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const _memPool = memPool.getMempool();
 | 
					    const _memPool = memPool.getMempool();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1014,6 +1016,8 @@ class WebsocketHandler {
 | 
				
			|||||||
        client.send(this.serializeResponse(response));
 | 
					        client.send(this.serializeResponse(response));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await statistics.runStatistics();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // takes a dictionary of JSON serialized values
 | 
					  // takes a dictionary of JSON serialized values
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
<div id="become-sponsor-container">
 | 
					<div id="become-sponsor-container" [ngClass]="context">
 | 
				
			||||||
  <div class="become-sponsor community">
 | 
					  <div class="become-sponsor community">
 | 
				
			||||||
    <p style="font-weight: 700; font-size: 18px;">If you're an individual...</p>
 | 
					    <p style="font-weight: 700; font-size: 18px;">If you're an individual...</p>
 | 
				
			||||||
    <a [href]="host + '/sponsor'" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.community-sponsor-button" (click)="onSponsorClick($event)">Become a Community Sponsor</a>
 | 
					    <a [href]="host + '/sponsor'" class="btn" style="background-color: rgba(152, 88, 255, 0.75); box-shadow: 0px 0px 50px 5px rgba(152, 88, 255, 0.75)" i18n="about.community-sponsor-button" (click)="onSponsorClick($event)">Become a Community Sponsor</a>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,11 @@
 | 
				
			|||||||
  align-items: center;
 | 
					  align-items: center;
 | 
				
			||||||
  gap: 20px;
 | 
					  gap: 20px;
 | 
				
			||||||
  margin: 68px auto;
 | 
					  margin: 68px auto;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#become-sponsor-container.account {
 | 
				
			||||||
 | 
					  margin: 20px auto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.become-sponsor {
 | 
					.become-sponsor {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ import { EnterpriseService } from '../../services/enterprise.service';
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
export class AboutSponsorsComponent {
 | 
					export class AboutSponsorsComponent {
 | 
				
			||||||
  @Input() host = 'https://mempool.space';
 | 
					  @Input() host = 'https://mempool.space';
 | 
				
			||||||
 | 
					  @Input() context = 'about';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(private enterpriseService: EnterpriseService) {
 | 
					  constructor(private enterpriseService: EnterpriseService) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -78,10 +78,7 @@
 | 
				
			|||||||
      <li class="nav-item" routerLinkActive="active" id="btn-assets">
 | 
					      <li class="nav-item" routerLinkActive="active" id="btn-assets">
 | 
				
			||||||
        <a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
 | 
					        <a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
 | 
				
			||||||
      </li>
 | 
					      </li>
 | 
				
			||||||
      <li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" id="btn-audit">
 | 
					      <li class="nav-item mr-2" routerLinkActive="active" id="btn-docs">
 | 
				
			||||||
        <a class="nav-link" [routerLink]="['/audit']" (click)="collapse()"><fa-icon [icon]="['fas', 'scale-balanced']" [fixedWidth]="true" i18n-title="master-page.btc-reserves-audit" title="BTC Reserves Audit"></fa-icon></a>
 | 
					 | 
				
			||||||
      </li>
 | 
					 | 
				
			||||||
      <li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active" id="btn-docs">
 | 
					 | 
				
			||||||
        <a class="nav-link" [routerLink]="['/docs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="master-page.docs" title="Docs"></fa-icon></a>
 | 
					        <a class="nav-link" [routerLink]="['/docs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="master-page.docs" title="Docs"></fa-icon></a>
 | 
				
			||||||
      </li>
 | 
					      </li>
 | 
				
			||||||
      <li class="nav-item" routerLinkActive="active" id="btn-about">
 | 
					      <li class="nav-item" routerLinkActive="active" id="btn-about">
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,11 @@ li.nav-item {
 | 
				
			|||||||
  margin: auto 10px;
 | 
					  margin: auto 10px;
 | 
				
			||||||
  padding-left: 10px;
 | 
					  padding-left: 10px;
 | 
				
			||||||
  padding-right: 10px;
 | 
					  padding-right: 10px;
 | 
				
			||||||
 | 
					  @media (max-width: 429px) {
 | 
				
			||||||
 | 
					    margin: auto 5px;
 | 
				
			||||||
 | 
					    padding-left: 6px;
 | 
				
			||||||
 | 
					    padding-right: 6px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media (min-width: 992px) {
 | 
					@media (min-width: 992px) {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,11 +6,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
tr, td, th {
 | 
					tr, td, th {
 | 
				
			||||||
  border: 0px;
 | 
					  border: 0px;
 | 
				
			||||||
  padding-top: 0.65rem !important;
 | 
					  padding-top: 0.65rem;
 | 
				
			||||||
  padding-bottom: 0.6rem !important;
 | 
					  padding-bottom: 0.6rem;
 | 
				
			||||||
  padding-right: 2rem !important;
 | 
					  padding-right: 2rem;
 | 
				
			||||||
  .widget {
 | 
					  .widget &.widget {
 | 
				
			||||||
    padding-right: 1rem !important;
 | 
					    padding-right: 1rem;
 | 
				
			||||||
 | 
					    @media (max-width: 510px) {
 | 
				
			||||||
 | 
					      padding-right: 0.5rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,12 @@
 | 
				
			|||||||
<div *ngIf="(federationAddresses$ | async) as federationAddresses; else loadingData">
 | 
					<div *ngIf="(federationWalletStats$ | async) as federationWalletStats; else loadingData">
 | 
				
			||||||
  
 | 
					 | 
				
			||||||
  <div class="fee-estimation-container">
 | 
					  <div class="fee-estimation-container">
 | 
				
			||||||
    <div class="item">
 | 
					    <div class="item">
 | 
				
			||||||
      <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]">
 | 
					      <a class="title-link" [routerLink]="['/audit/wallet/addresses' | relativeUrl]">
 | 
				
			||||||
        <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
					        <h5 class="card-title"><ng-container i18n="liquid.federation-wallet">Liquid Federation Wallet</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
      <div class="card-text">
 | 
					      <div class="card-text">
 | 
				
			||||||
          <div class="fee-text">{{ federationAddresses.length }} <span i18n="shared.addresses">addresses</span></div>
 | 
					        <div class="fee-text">{{ federationWalletStats.address_count }} <span i18n="shared.addresses">addresses</span></div>
 | 
				
			||||||
          <span class="fiat" *ngIf="(federationAddressesOneMonthAgo$ | async) as federationAddressesOneMonthAgo; else loadingSkeleton" i18n-ngbTooltip="liquid.percentage-change-last-month" ngbTooltip="Percentage change past month" placement="bottom">
 | 
					        <div class="fiat">{{ federationWalletStats.utxo_count }} <span i18n="shared.utxos">UTXOs</span></div>
 | 
				
			||||||
            <app-change [current]="federationAddresses.length" [previous]="federationAddressesOneMonthAgo.addresses_count_one_month"></app-change>
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
@ -30,5 +27,5 @@
 | 
				
			|||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #loadingSkeleton>
 | 
					<ng-template #loadingSkeleton>
 | 
				
			||||||
  <div class="skeleton-loader skeleton-loader-transactions" style="margin-top: 2px; margin-bottom: 5px;"></div>
 | 
					  <div class="skeleton-loader skeleton-loader-transactions" style="margin-top: 8px; margin-bottom: 8px;"></div>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
.fee-estimation-container {
 | 
					.fee-estimation-container {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: space-between;
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
  @media (min-width: 376px) {
 | 
					  @media (min-width: 376px) {
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: row;
 | 
				
			||||||
  }  
 | 
					  }  
 | 
				
			||||||
@ -21,6 +22,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .card-text {
 | 
					    .card-text {
 | 
				
			||||||
 | 
					      padding-top: 9px;
 | 
				
			||||||
      font-size: 22px;
 | 
					      font-size: 22px;
 | 
				
			||||||
      span {
 | 
					      span {
 | 
				
			||||||
        font-size: 11px;
 | 
					        font-size: 11px;
 | 
				
			||||||
@ -48,10 +50,6 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.loading-container{
 | 
					 | 
				
			||||||
  min-height: 76px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card-text {
 | 
					.card-text {
 | 
				
			||||||
  .skeleton-loader {
 | 
					  .skeleton-loader {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 | 
					import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 | 
				
			||||||
import { Observable } from 'rxjs';
 | 
					import { Observable, combineLatest, map, of } from 'rxjs';
 | 
				
			||||||
import { FederationAddress } from '../../../interfaces/node-api.interface';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-federation-addresses-stats',
 | 
					  selector: 'app-federation-addresses-stats',
 | 
				
			||||||
@ -9,12 +8,24 @@ import { FederationAddress } from '../../../interfaces/node-api.interface';
 | 
				
			|||||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
					  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class FederationAddressesStatsComponent implements OnInit {
 | 
					export class FederationAddressesStatsComponent implements OnInit {
 | 
				
			||||||
  @Input() federationAddresses$: Observable<FederationAddress[]>;
 | 
					  @Input() federationAddressesNumber$: Observable<number>;
 | 
				
			||||||
  @Input() federationAddressesOneMonthAgo$: Observable<any>;
 | 
					  @Input() federationUtxosNumber$: Observable<number>;
 | 
				
			||||||
 | 
					  federationWalletStats$: Observable<any>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
					    this.federationWalletStats$ = combineLatest([
 | 
				
			||||||
 | 
					      this.federationAddressesNumber$ ?? of(undefined),
 | 
				
			||||||
 | 
					      this.federationUtxosNumber$ ?? of(undefined)
 | 
				
			||||||
 | 
					    ]).pipe(
 | 
				
			||||||
 | 
					      map(([address_count, utxo_count]) => {
 | 
				
			||||||
 | 
					        if (address_count === undefined || utxo_count === undefined) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return { address_count, utxo_count}
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
<div class="container-xl">
 | 
					<div [ngClass]="{'container-xl': !widget, 'widget': widget}">
 | 
				
			||||||
  <div [ngClass]="{'widget': widget}">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div *ngIf="!widget">
 | 
					  <div *ngIf="!widget">
 | 
				
			||||||
    <h1 i18n="liquid.recent-pegs">Recent Peg-In / Out's</h1>
 | 
					    <h1 i18n="liquid.recent-pegs">Recent Peg-In / Out's</h1>
 | 
				
			||||||
@ -16,7 +15,7 @@
 | 
				
			|||||||
        <th class="output text-left" *ngIf="!widget" i18n="liquid.fund-redemption-tx">Fund / Redemption Tx</th>
 | 
					        <th class="output text-left" *ngIf="!widget" i18n="liquid.fund-redemption-tx">Fund / Redemption Tx</th>
 | 
				
			||||||
        <th class="address text-left" *ngIf="!widget" i18n="liquid.bitcoin-address">BTC Address</th>
 | 
					        <th class="address text-left" *ngIf="!widget" i18n="liquid.bitcoin-address">BTC Address</th>
 | 
				
			||||||
      </thead>
 | 
					      </thead>
 | 
				
			||||||
        <tbody *ngIf="recentPegs$ | async as pegs; else skeleton" [style]="isLoading ? 'opacity: 0.75' : ''">
 | 
					      <tbody *ngIf="recentPegsList$ | async as pegs; else skeleton" [style]="isLoading ? 'opacity: 0.75' : ''">
 | 
				
			||||||
        <ng-container *ngIf="widget; else regularRows">
 | 
					        <ng-container *ngIf="widget; else regularRows">
 | 
				
			||||||
          <tr *ngFor="let peg of pegs | slice:0:5">
 | 
					          <tr *ngFor="let peg of pegs | slice:0:5">
 | 
				
			||||||
            <td class="transaction text-left widget">
 | 
					            <td class="transaction text-left widget">
 | 
				
			||||||
@ -40,7 +39,7 @@
 | 
				
			|||||||
          </tr>
 | 
					          </tr>
 | 
				
			||||||
        </ng-container>
 | 
					        </ng-container>
 | 
				
			||||||
        <ng-template #regularRows>
 | 
					        <ng-template #regularRows>
 | 
				
			||||||
            <tr *ngFor="let peg of pegs | slice:(page - 1) * pageSize:page * pageSize">
 | 
					          <tr *ngFor="let peg of pegs;">
 | 
				
			||||||
            <td class="transaction text-left">
 | 
					            <td class="transaction text-left">
 | 
				
			||||||
              <ng-container *ngIf="peg.amount > 0">
 | 
					              <ng-container *ngIf="peg.amount > 0">
 | 
				
			||||||
                <a [routerLink]="['/tx' | relativeUrl, peg.txid]" [fragment]="'vin=' + peg.txindex">
 | 
					                <a [routerLink]="['/tx' | relativeUrl, peg.txid]" [fragment]="'vin=' + peg.txindex">
 | 
				
			||||||
@ -102,7 +101,7 @@
 | 
				
			|||||||
              <span class="skeleton-loader" style="max-width: 300px"></span>
 | 
					              <span class="skeleton-loader" style="max-width: 300px"></span>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <td class="timestamp text-left">
 | 
					            <td class="timestamp text-left">
 | 
				
			||||||
                <span class="skeleton-loader" style="max-width: 140px"></span>
 | 
					              <span class="skeleton-loader" style="max-width: 240px"></span>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <td class="amount text-right">
 | 
					            <td class="amount text-right">
 | 
				
			||||||
              <span class="skeleton-loader" style="max-width: 140px"></span>
 | 
					              <span class="skeleton-loader" style="max-width: 140px"></span>
 | 
				
			||||||
@ -111,15 +110,15 @@
 | 
				
			|||||||
              <span class="skeleton-loader" style="max-width: 300px"></span>
 | 
					              <span class="skeleton-loader" style="max-width: 300px"></span>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <td class="address text-left">
 | 
					            <td class="address text-left">
 | 
				
			||||||
                <span class="skeleton-loader" style="max-width: 140px"></span>
 | 
					              <span class="skeleton-loader" style="max-width: 240px"></span>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
          </tr>
 | 
					          </tr>
 | 
				
			||||||
        </ng-template>
 | 
					        </ng-template>
 | 
				
			||||||
      </ng-template>
 | 
					      </ng-template>
 | 
				
			||||||
    </table>
 | 
					    </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <ngb-pagination *ngIf="!widget && recentPegs$ | async as pegs" class="pagination-container float-right mt-2" [class]="isLoading ? 'disabled' : ''"
 | 
					    <ngb-pagination *ngIf="!widget && pegsCount$ | async as pegsCount" class="pagination-container float-right mt-2" [class]="isLoading || isPegCountLoading ? 'disabled' : ''"
 | 
				
			||||||
        [collectionSize]="pegs.length" [rotate]="true" [maxSize]="maxSize" [pageSize]="15" [(page)]="page"
 | 
					      [collectionSize]="pegsCount" [rotate]="true" [maxSize]="maxSize" [pageSize]="15" [(page)]="page"
 | 
				
			||||||
      (pageChange)="pageChange(page)" [boundaryLinks]="true" [ellipses]="false">
 | 
					      (pageChange)="pageChange(page)" [boundaryLinks]="true" [ellipses]="false">
 | 
				
			||||||
    </ngb-pagination>
 | 
					    </ngb-pagination>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -129,7 +128,6 @@
 | 
				
			|||||||
    </ng-template>
 | 
					    </ng-template>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<br>
 | 
					<br>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,11 +6,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
tr, td, th {
 | 
					tr, td, th {
 | 
				
			||||||
  border: 0px;
 | 
					  border: 0px;
 | 
				
			||||||
  padding-top: 0.65rem !important;
 | 
					  padding-top: 0.65rem;
 | 
				
			||||||
  padding-bottom: 0.6rem !important;
 | 
					  padding-bottom: 0.6rem;
 | 
				
			||||||
  padding-right: 2rem !important;
 | 
					  padding-right: 2rem;
 | 
				
			||||||
  .widget {
 | 
					  .widget &.widget {
 | 
				
			||||||
    padding-right: 1rem !important;
 | 
					    padding-right: 1rem;
 | 
				
			||||||
 | 
					    @media (max-width: 510px) {
 | 
				
			||||||
 | 
					      padding-right: 0.5rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,7 +96,7 @@ tr, td, th {
 | 
				
			|||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @media (max-width: 500px) {
 | 
					  @media (max-width: 510px) {
 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
 | 
					import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
 | 
				
			||||||
import { Observable, Subject, combineLatest, of, timer } from 'rxjs';
 | 
					import { BehaviorSubject, Observable, Subject, combineLatest, of, timer } from 'rxjs';
 | 
				
			||||||
import { delayWhen, filter, map, share, shareReplay, switchMap, takeUntil, tap, throttleTime } from 'rxjs/operators';
 | 
					import { delayWhen, filter, map, share, shareReplay, switchMap, takeUntil, tap, throttleTime } from 'rxjs/operators';
 | 
				
			||||||
import { ApiService } from '../../../services/api.service';
 | 
					import { ApiService } from '../../../services/api.service';
 | 
				
			||||||
import { Env, StateService } from '../../../services/state.service';
 | 
					import { Env, StateService } from '../../../services/state.service';
 | 
				
			||||||
import { AuditStatus, CurrentPegs, FederationUtxo, RecentPeg } from '../../../interfaces/node-api.interface';
 | 
					import { AuditStatus, CurrentPegs, RecentPeg } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
import { WebsocketService } from '../../../services/websocket.service';
 | 
					import { WebsocketService } from '../../../services/websocket.service';
 | 
				
			||||||
import { SeoService } from '../../../services/seo.service';
 | 
					import { SeoService } from '../../../services/seo.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -15,21 +15,22 @@ import { SeoService } from '../../../services/seo.service';
 | 
				
			|||||||
})
 | 
					})
 | 
				
			||||||
export class RecentPegsListComponent implements OnInit {
 | 
					export class RecentPegsListComponent implements OnInit {
 | 
				
			||||||
  @Input() widget: boolean = false;
 | 
					  @Input() widget: boolean = false;
 | 
				
			||||||
  @Input() recentPegIns$: Observable<RecentPeg[]> = of([]);
 | 
					  @Input() recentPegsList$: Observable<RecentPeg[]>;
 | 
				
			||||||
  @Input() recentPegOuts$: Observable<RecentPeg[]> = of([]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  env: Env;
 | 
					  env: Env;
 | 
				
			||||||
  isLoading = true;
 | 
					  isLoading = true;
 | 
				
			||||||
 | 
					  isPegCountLoading = true;
 | 
				
			||||||
  page = 1;
 | 
					  page = 1;
 | 
				
			||||||
  pageSize = 15;
 | 
					  pageSize = 15;
 | 
				
			||||||
  maxSize = window.innerWidth <= 767.98 ? 3 : 5;
 | 
					  maxSize = window.innerWidth <= 767.98 ? 3 : 5;
 | 
				
			||||||
  skeletonLines: number[] = [];
 | 
					  skeletonLines: number[] = [];
 | 
				
			||||||
  auditStatus$: Observable<AuditStatus>;
 | 
					  auditStatus$: Observable<AuditStatus>;
 | 
				
			||||||
  auditUpdated$: Observable<boolean>;
 | 
					  auditUpdated$: Observable<boolean>;
 | 
				
			||||||
  federationUtxos$: Observable<FederationUtxo[]>;
 | 
					 | 
				
			||||||
  recentPegs$: Observable<RecentPeg[]>;
 | 
					 | 
				
			||||||
  lastReservesBlockUpdate: number = 0;
 | 
					  lastReservesBlockUpdate: number = 0;
 | 
				
			||||||
  currentPeg$: Observable<CurrentPegs>;
 | 
					  currentPeg$: Observable<CurrentPegs>;
 | 
				
			||||||
 | 
					  pegsCount$: Observable<number>;
 | 
				
			||||||
 | 
					  startingIndexSubject: BehaviorSubject<number> = new BehaviorSubject(0);
 | 
				
			||||||
 | 
					  currentIndex: number = 0;
 | 
				
			||||||
  lastPegBlockUpdate: number = 0;
 | 
					  lastPegBlockUpdate: number = 0;
 | 
				
			||||||
  lastPegAmount: string = '';
 | 
					  lastPegAmount: string = '';
 | 
				
			||||||
  isLoad: boolean = true;
 | 
					  isLoad: boolean = true;
 | 
				
			||||||
@ -93,53 +94,36 @@ export class RecentPegsListComponent implements OnInit {
 | 
				
			|||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.federationUtxos$ = this.auditUpdated$.pipe(
 | 
					      this.pegsCount$ = this.auditUpdated$.pipe(
 | 
				
			||||||
        filter(auditUpdated => auditUpdated === true),
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
        throttleTime(40000),
 | 
					        tap(() => this.isPegCountLoading = true),
 | 
				
			||||||
        switchMap(_ => this.apiService.federationUtxos$()),
 | 
					        switchMap(_ => this.apiService.pegsCount$()),
 | 
				
			||||||
 | 
					        map((data) => data.pegs_count),
 | 
				
			||||||
 | 
					        tap(() => this.isPegCountLoading = false),
 | 
				
			||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.recentPegIns$ = this.federationUtxos$.pipe(
 | 
					      this.recentPegsList$ = combineLatest([
 | 
				
			||||||
        map(federationUtxos => federationUtxos.filter(utxo => utxo.pegtxid).map(utxo => {
 | 
					        this.auditStatus$,
 | 
				
			||||||
          return {
 | 
					        this.auditUpdated$,
 | 
				
			||||||
            txid: utxo.pegtxid,
 | 
					        this.startingIndexSubject
 | 
				
			||||||
            txindex: utxo.pegindex,
 | 
					 | 
				
			||||||
            amount: utxo.amount,
 | 
					 | 
				
			||||||
            bitcoinaddress: utxo.bitcoinaddress,
 | 
					 | 
				
			||||||
            bitcointxid: utxo.txid,
 | 
					 | 
				
			||||||
            bitcoinindex: utxo.txindex,
 | 
					 | 
				
			||||||
            blocktime: utxo.pegblocktime,
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        })),
 | 
					 | 
				
			||||||
        share()
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this.recentPegOuts$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
        filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
        throttleTime(40000),
 | 
					 | 
				
			||||||
        switchMap(_ => this.apiService.recentPegOuts$()),
 | 
					 | 
				
			||||||
        share()
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.recentPegs$ = combineLatest([
 | 
					 | 
				
			||||||
      this.recentPegIns$,
 | 
					 | 
				
			||||||
      this.recentPegOuts$
 | 
					 | 
				
			||||||
      ]).pipe(
 | 
					      ]).pipe(
 | 
				
			||||||
      map(([recentPegIns, recentPegOuts]) => {
 | 
					        filter(([auditStatus, auditUpdated, startingIndex]) => {
 | 
				
			||||||
        return [
 | 
					          const auditStatusCheck = auditStatus.isAuditSynced === true;
 | 
				
			||||||
          ...recentPegIns,
 | 
					          const auditUpdatedCheck = auditUpdated === true;
 | 
				
			||||||
          ...recentPegOuts
 | 
					          const startingIndexCheck = startingIndex !== this.currentIndex;
 | 
				
			||||||
        ].sort((a, b) => {
 | 
					          return auditStatusCheck && (auditUpdatedCheck || startingIndexCheck);
 | 
				
			||||||
          return b.blocktime - a.blocktime;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
      filter(recentPegs => recentPegs.length > 0),
 | 
					        tap(([_, __, startingIndex]) => {
 | 
				
			||||||
      tap(_ => this.isLoading = false),
 | 
					          this.currentIndex = startingIndex;
 | 
				
			||||||
 | 
					          this.isLoading = true;
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        switchMap(([_, __, startingIndex]) => this.apiService.recentPegsList$(startingIndex)),
 | 
				
			||||||
 | 
					        tap(() => this.isLoading = false),
 | 
				
			||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnDestroy(): void {
 | 
					  ngOnDestroy(): void {
 | 
				
			||||||
@ -148,6 +132,7 @@ export class RecentPegsListComponent implements OnInit {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pageChange(page: number): void {
 | 
					  pageChange(page: number): void {
 | 
				
			||||||
 | 
					    this.startingIndexSubject.next((page - 1) * 15);
 | 
				
			||||||
    this.page = page;
 | 
					    this.page = page;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
.fee-estimation-container {
 | 
					.fee-estimation-container {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: space-between;
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  margin-bottom: 10px;
 | 
				
			||||||
  @media (min-width: 376px) {
 | 
					  @media (min-width: 376px) {
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: row;
 | 
				
			||||||
  }  
 | 
					  }  
 | 
				
			||||||
 | 
				
			|||||||
@ -1,98 +0,0 @@
 | 
				
			|||||||
<div class="container-xl dashboard-container" *ngIf="(auditStatus$ | async)?.isAuditSynced; else auditInProgress">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <div class="row row-cols-1 row-cols-md-2">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="col">
 | 
					 | 
				
			||||||
      <div class="card">
 | 
					 | 
				
			||||||
        <div class="card-body">
 | 
					 | 
				
			||||||
          <app-reserves-supply-stats [currentPeg$]="currentPeg$" [currentReserves$]="currentReserves$"></app-reserves-supply-stats>
 | 
					 | 
				
			||||||
          <app-reserves-ratio [currentPeg]="currentPeg$ | async" [currentReserves]="currentReserves$ | async"></app-reserves-ratio>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="col" style="margin-bottom: 1.47rem">
 | 
					 | 
				
			||||||
      <div class="card"> 
 | 
					 | 
				
			||||||
        <div class="card-title">
 | 
					 | 
				
			||||||
          <app-reserves-ratio-stats [fullHistory$]="fullHistory$"></app-reserves-ratio-stats>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="card-body pl-0" style="padding-top: 10px;">
 | 
					 | 
				
			||||||
          <app-reserves-ratio-graph [data]="fullHistory$ | async"></app-reserves-ratio-graph>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="col">
 | 
					 | 
				
			||||||
      <div class="card">
 | 
					 | 
				
			||||||
        <div class="card-body">
 | 
					 | 
				
			||||||
          <app-recent-pegs-stats [pegsVolume$]="pegsVolume$"></app-recent-pegs-stats>
 | 
					 | 
				
			||||||
          <app-recent-pegs-list [recentPegIns$]="recentPegIns$" [recentPegOuts$]="recentPegOuts$"[widget]="true"></app-recent-pegs-list>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="col" style="margin-bottom: 1.47rem">
 | 
					 | 
				
			||||||
      <div class="card">
 | 
					 | 
				
			||||||
        <div class="card-body">
 | 
					 | 
				
			||||||
          <app-federation-addresses-stats [federationAddresses$]="federationAddresses$" [federationAddressesOneMonthAgo$]="federationAddressesOneMonthAgo$"></app-federation-addresses-stats>
 | 
					 | 
				
			||||||
          <app-federation-addresses-list [federationAddresses$]="federationAddresses$" [widget]="true"></app-federation-addresses-list>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<ng-template #loadingSkeleton>
 | 
					 | 
				
			||||||
  <div class="container-xl dashboard-container">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="row row-cols-1 row-cols-md-2">
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
      <div class="col">
 | 
					 | 
				
			||||||
        <div class="card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <app-reserves-supply-stats></app-reserves-supply-stats>
 | 
					 | 
				
			||||||
            <app-reserves-ratio></app-reserves-ratio>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      <div class="col" style="margin-bottom: 1.47rem">
 | 
					 | 
				
			||||||
        <div class="card"> 
 | 
					 | 
				
			||||||
          <div class="card-title">
 | 
					 | 
				
			||||||
            <app-reserves-ratio-stats></app-reserves-ratio-stats>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div class="card-body pl-0" style="padding-top: 10px;">
 | 
					 | 
				
			||||||
            <app-reserves-ratio-graph></app-reserves-ratio-graph>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
      <div class="col">
 | 
					 | 
				
			||||||
        <div class="card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <app-recent-pegs-stats></app-recent-pegs-stats>
 | 
					 | 
				
			||||||
            <app-recent-pegs-list [widget]="true"></app-recent-pegs-list>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
      <div class="col" style="margin-bottom: 1.47rem">
 | 
					 | 
				
			||||||
        <div class="card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <app-federation-addresses-stats></app-federation-addresses-stats>
 | 
					 | 
				
			||||||
            <app-federation-addresses-list [widget]="true"></app-federation-addresses-list>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</ng-template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<ng-template #auditInProgress>
 | 
					 | 
				
			||||||
  <ng-container *ngIf="(auditStatus$ | async) as auditStatus; else loadingSkeleton">
 | 
					 | 
				
			||||||
    <div class="in-progress-message" *ngIf="auditStatus.lastBlockAudit && auditStatus.bitcoinHeaders; else loadingSkeleton">
 | 
					 | 
				
			||||||
      <span i18n="liquid.audit-in-progress">Audit in progress: Bitcoin block height #{{ auditStatus.lastBlockAudit }} / #{{ auditStatus.bitcoinHeaders }}</span>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </ng-container>
 | 
					 | 
				
			||||||
</ng-template>
 | 
					 | 
				
			||||||
@ -1,138 +0,0 @@
 | 
				
			|||||||
.dashboard-container {
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  margin-top: 0.5rem;
 | 
					 | 
				
			||||||
  .col {
 | 
					 | 
				
			||||||
    margin-bottom: 1.5rem;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card {
 | 
					 | 
				
			||||||
  background-color: #1d1f31;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card-title {
 | 
					 | 
				
			||||||
  padding-top: 20px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card-body.pool-ranking {
 | 
					 | 
				
			||||||
  padding: 1.25rem 0.25rem 0.75rem 0.25rem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.card-text {
 | 
					 | 
				
			||||||
  font-size: 22px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#blockchain-container {
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
  overflow-x: scroll;
 | 
					 | 
				
			||||||
  overflow-y: hidden;
 | 
					 | 
				
			||||||
  scrollbar-width: none;
 | 
					 | 
				
			||||||
  -ms-overflow-style: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#blockchain-container::-webkit-scrollbar {
 | 
					 | 
				
			||||||
  display: none;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.fade-border {
 | 
					 | 
				
			||||||
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 80%, transparent 100%)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.in-progress-message {
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
  color: #ffffff91;
 | 
					 | 
				
			||||||
  margin-top: 20px;
 | 
					 | 
				
			||||||
  text-align: center;
 | 
					 | 
				
			||||||
  padding-bottom: 3px;
 | 
					 | 
				
			||||||
  font-weight: 500;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.more-padding {
 | 
					 | 
				
			||||||
  padding: 24px 20px !important;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card-wrapper {
 | 
					 | 
				
			||||||
  .card {
 | 
					 | 
				
			||||||
    height: auto !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .card-body {
 | 
					 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
    flex: inherit;
 | 
					 | 
				
			||||||
    text-align: center;
 | 
					 | 
				
			||||||
    flex-direction: column;
 | 
					 | 
				
			||||||
    justify-content: space-around;
 | 
					 | 
				
			||||||
    padding: 22px 20px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.skeleton-loader {
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  display: block;
 | 
					 | 
				
			||||||
  &:first-child {
 | 
					 | 
				
			||||||
    max-width: 90px;
 | 
					 | 
				
			||||||
    margin: 15px auto 3px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  &:last-child {
 | 
					 | 
				
			||||||
    margin: 10px auto 3px;
 | 
					 | 
				
			||||||
    max-width: 55px;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card-text {
 | 
					 | 
				
			||||||
  font-size: 22px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.title-link, .title-link:hover, .title-link:focus, .title-link:active {
 | 
					 | 
				
			||||||
  display: block;
 | 
					 | 
				
			||||||
  margin-bottom: 10px;
 | 
					 | 
				
			||||||
  text-decoration: none;
 | 
					 | 
				
			||||||
  color: inherit;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.lastest-blocks-table {
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  text-align: left;
 | 
					 | 
				
			||||||
  tr, td, th {
 | 
					 | 
				
			||||||
    border: 0px;
 | 
					 | 
				
			||||||
    padding-top: 0.65rem !important;
 | 
					 | 
				
			||||||
    padding-bottom: 0.8rem !important;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .table-cell-height {
 | 
					 | 
				
			||||||
    width: 25%;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .table-cell-fee {
 | 
					 | 
				
			||||||
    width: 25%;
 | 
					 | 
				
			||||||
    text-align: right;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .table-cell-pool {
 | 
					 | 
				
			||||||
    text-align: left;
 | 
					 | 
				
			||||||
    width: 30%;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @media (max-width: 875px) {
 | 
					 | 
				
			||||||
      display: none;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .pool-name {
 | 
					 | 
				
			||||||
      margin-left: 1em;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  .table-cell-acceleration-count {
 | 
					 | 
				
			||||||
    text-align: right;
 | 
					 | 
				
			||||||
    width: 20%;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.card {
 | 
					 | 
				
			||||||
  height: 385px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.list-card {
 | 
					 | 
				
			||||||
  height: 410px;
 | 
					 | 
				
			||||||
  @media (max-width: 767px) {
 | 
					 | 
				
			||||||
    height: auto;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.mempool-block-wrapper {
 | 
					 | 
				
			||||||
  max-height: 380px;
 | 
					 | 
				
			||||||
  max-width: 380px;
 | 
					 | 
				
			||||||
  margin: auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,212 +0,0 @@
 | 
				
			|||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
					 | 
				
			||||||
import { SeoService } from '../../../services/seo.service';
 | 
					 | 
				
			||||||
import { WebsocketService } from '../../../services/websocket.service';
 | 
					 | 
				
			||||||
import { StateService } from '../../../services/state.service';
 | 
					 | 
				
			||||||
import { Observable, Subject, combineLatest, delayWhen, filter, interval, map, of, share, shareReplay, startWith, switchMap, takeUntil, tap, throttleTime, timer } from 'rxjs';
 | 
					 | 
				
			||||||
import { ApiService } from '../../../services/api.service';
 | 
					 | 
				
			||||||
import { AuditStatus, CurrentPegs, FederationAddress, FederationUtxo, PegsVolume, RecentPeg } from '../../../interfaces/node-api.interface';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Component({
 | 
					 | 
				
			||||||
  selector: 'app-reserves-audit-dashboard',
 | 
					 | 
				
			||||||
  templateUrl: './reserves-audit-dashboard.component.html',
 | 
					 | 
				
			||||||
  styleUrls: ['./reserves-audit-dashboard.component.scss'],
 | 
					 | 
				
			||||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class ReservesAuditDashboardComponent implements OnInit {
 | 
					 | 
				
			||||||
  auditStatus$: Observable<AuditStatus>;
 | 
					 | 
				
			||||||
  auditUpdated$: Observable<boolean>;
 | 
					 | 
				
			||||||
  currentPeg$: Observable<CurrentPegs>;
 | 
					 | 
				
			||||||
  currentReserves$: Observable<CurrentPegs>;
 | 
					 | 
				
			||||||
  federationUtxos$: Observable<FederationUtxo[]>;
 | 
					 | 
				
			||||||
  recentPegIns$: Observable<RecentPeg[]>;
 | 
					 | 
				
			||||||
  recentPegOuts$: Observable<RecentPeg[]>;
 | 
					 | 
				
			||||||
  pegsVolume$: Observable<PegsVolume[]>;
 | 
					 | 
				
			||||||
  federationAddresses$: Observable<FederationAddress[]>;
 | 
					 | 
				
			||||||
  federationAddressesOneMonthAgo$: Observable<any>;
 | 
					 | 
				
			||||||
  liquidPegsMonth$: Observable<any>;
 | 
					 | 
				
			||||||
  liquidReservesMonth$: Observable<any>;
 | 
					 | 
				
			||||||
  fullHistory$: Observable<any>;
 | 
					 | 
				
			||||||
  isLoad: boolean = true;
 | 
					 | 
				
			||||||
  private lastPegBlockUpdate: number = 0;
 | 
					 | 
				
			||||||
  private lastPegAmount: string = '';
 | 
					 | 
				
			||||||
  private lastReservesBlockUpdate: number = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private destroy$ = new Subject();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  constructor(
 | 
					 | 
				
			||||||
    private seoService: SeoService,
 | 
					 | 
				
			||||||
    private websocketService: WebsocketService,
 | 
					 | 
				
			||||||
    private apiService: ApiService,
 | 
					 | 
				
			||||||
    private stateService: StateService,
 | 
					 | 
				
			||||||
  ) {
 | 
					 | 
				
			||||||
    this.seoService.setTitle($localize`:@@liquid.reserves-audit:Reserves Audit Dashboard`);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnInit(): void {
 | 
					 | 
				
			||||||
    this.websocketService.want(['blocks', 'mempool-blocks']);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.auditStatus$ = this.stateService.blocks$.pipe(
 | 
					 | 
				
			||||||
      takeUntil(this.destroy$),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      delayWhen(_ => this.isLoad ? timer(0) : timer(2000)),
 | 
					 | 
				
			||||||
      tap(() => this.isLoad = false),
 | 
					 | 
				
			||||||
      switchMap(() => this.apiService.federationAuditSynced$()),
 | 
					 | 
				
			||||||
      shareReplay(1),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.currentPeg$ = this.auditStatus$.pipe(
 | 
					 | 
				
			||||||
      filter(auditStatus => auditStatus.isAuditSynced === true),
 | 
					 | 
				
			||||||
      switchMap(_ =>
 | 
					 | 
				
			||||||
        this.apiService.liquidPegs$().pipe(
 | 
					 | 
				
			||||||
          filter((currentPegs) => currentPegs.lastBlockUpdate >= this.lastPegBlockUpdate),
 | 
					 | 
				
			||||||
          tap((currentPegs) => {
 | 
					 | 
				
			||||||
            this.lastPegBlockUpdate = currentPegs.lastBlockUpdate;
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.auditUpdated$ = combineLatest([
 | 
					 | 
				
			||||||
      this.auditStatus$,
 | 
					 | 
				
			||||||
      this.currentPeg$
 | 
					 | 
				
			||||||
    ]).pipe(
 | 
					 | 
				
			||||||
      filter(([auditStatus, _]) => auditStatus.isAuditSynced === true),
 | 
					 | 
				
			||||||
      map(([auditStatus, currentPeg]) => ({
 | 
					 | 
				
			||||||
        lastBlockAudit: auditStatus.lastBlockAudit,
 | 
					 | 
				
			||||||
        currentPegAmount: currentPeg.amount
 | 
					 | 
				
			||||||
      })),
 | 
					 | 
				
			||||||
      switchMap(({ lastBlockAudit, currentPegAmount }) => {
 | 
					 | 
				
			||||||
        const blockAuditCheck = lastBlockAudit > this.lastReservesBlockUpdate;
 | 
					 | 
				
			||||||
        const amountCheck = currentPegAmount !== this.lastPegAmount;
 | 
					 | 
				
			||||||
        this.lastPegAmount = currentPegAmount;
 | 
					 | 
				
			||||||
        return of(blockAuditCheck || amountCheck);
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.currentReserves$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
      filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      switchMap(_ =>
 | 
					 | 
				
			||||||
        this.apiService.liquidReserves$().pipe(
 | 
					 | 
				
			||||||
          filter((currentReserves) => currentReserves.lastBlockUpdate >= this.lastReservesBlockUpdate),
 | 
					 | 
				
			||||||
          tap((currentReserves) => {
 | 
					 | 
				
			||||||
            this.lastReservesBlockUpdate = currentReserves.lastBlockUpdate;
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.federationUtxos$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
      filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      switchMap(_ => this.apiService.federationUtxos$()),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.recentPegIns$ = this.federationUtxos$.pipe(
 | 
					 | 
				
			||||||
      map(federationUtxos => federationUtxos.filter(utxo => utxo.pegtxid).map(utxo => {
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
          txid: utxo.pegtxid,
 | 
					 | 
				
			||||||
          txindex: utxo.pegindex,
 | 
					 | 
				
			||||||
          amount: utxo.amount,
 | 
					 | 
				
			||||||
          bitcoinaddress: utxo.bitcoinaddress,
 | 
					 | 
				
			||||||
          bitcointxid: utxo.txid,
 | 
					 | 
				
			||||||
          bitcoinindex: utxo.txindex,
 | 
					 | 
				
			||||||
          blocktime: utxo.pegblocktime,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      })),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.recentPegOuts$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
      filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      switchMap(_ => this.apiService.recentPegOuts$()),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.pegsVolume$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
      filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      switchMap(_ => this.apiService.pegsVolume$()),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.federationAddresses$ = this.auditUpdated$.pipe(
 | 
					 | 
				
			||||||
      filter(auditUpdated => auditUpdated === true),
 | 
					 | 
				
			||||||
      throttleTime(40000),
 | 
					 | 
				
			||||||
      switchMap(_ => this.apiService.federationAddresses$()),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.federationAddressesOneMonthAgo$ = interval(60 * 60 * 1000)
 | 
					 | 
				
			||||||
      .pipe(
 | 
					 | 
				
			||||||
        startWith(0),
 | 
					 | 
				
			||||||
        switchMap(() => this.apiService.federationAddressesOneMonthAgo$())
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.liquidPegsMonth$ = interval(60 * 60 * 1000)
 | 
					 | 
				
			||||||
      .pipe(
 | 
					 | 
				
			||||||
        startWith(0),
 | 
					 | 
				
			||||||
        switchMap(() => this.apiService.listLiquidPegsMonth$()),
 | 
					 | 
				
			||||||
        map((pegs) => {
 | 
					 | 
				
			||||||
          const labels = pegs.map(stats => stats.date);
 | 
					 | 
				
			||||||
          const series = pegs.map(stats => parseFloat(stats.amount) / 100000000);
 | 
					 | 
				
			||||||
          series.reduce((prev, curr, i) => series[i] = prev + curr, 0);
 | 
					 | 
				
			||||||
          return {
 | 
					 | 
				
			||||||
            series,
 | 
					 | 
				
			||||||
            labels
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        share(),
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.liquidReservesMonth$ = interval(60 * 60 * 1000).pipe(
 | 
					 | 
				
			||||||
      startWith(0),
 | 
					 | 
				
			||||||
      switchMap(() => this.apiService.listLiquidReservesMonth$()),
 | 
					 | 
				
			||||||
      map(reserves => {
 | 
					 | 
				
			||||||
        const labels = reserves.map(stats => stats.date);
 | 
					 | 
				
			||||||
        const series = reserves.map(stats => parseFloat(stats.amount) / 100000000);
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
          series,
 | 
					 | 
				
			||||||
          labels
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
      share()
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.fullHistory$ = combineLatest([this.liquidPegsMonth$, this.currentPeg$, this.liquidReservesMonth$, this.currentReserves$])
 | 
					 | 
				
			||||||
      .pipe(
 | 
					 | 
				
			||||||
        map(([liquidPegs, currentPeg, liquidReserves, currentReserves]) => {
 | 
					 | 
				
			||||||
          liquidPegs.series[liquidPegs.series.length - 1] = parseFloat(currentPeg.amount) / 100000000;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (liquidPegs.series.length === liquidReserves?.series.length) {
 | 
					 | 
				
			||||||
            liquidReserves.series[liquidReserves.series.length - 1] = parseFloat(currentReserves?.amount) / 100000000;
 | 
					 | 
				
			||||||
          } else if (liquidPegs.series.length === liquidReserves?.series.length + 1) {
 | 
					 | 
				
			||||||
            liquidReserves.series.push(parseFloat(currentReserves?.amount) / 100000000);
 | 
					 | 
				
			||||||
            liquidReserves.labels.push(liquidPegs.labels[liquidPegs.labels.length - 1]);
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            liquidReserves = {
 | 
					 | 
				
			||||||
              series: [],
 | 
					 | 
				
			||||||
              labels: []
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          return {
 | 
					 | 
				
			||||||
            liquidPegs,
 | 
					 | 
				
			||||||
            liquidReserves
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        share()
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnDestroy(): void {
 | 
					 | 
				
			||||||
    this.destroy$.next(1);
 | 
					 | 
				
			||||||
    this.destroy$.complete();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
        <h5 class="card-title" i18n="liquid.avg-peg-ratio">Avg Peg Ratio</h5> 
 | 
					        <h5 class="card-title" i18n="liquid.avg-peg-ratio">Avg Peg Ratio</h5> 
 | 
				
			||||||
        <div class="card-text">
 | 
					        <div class="card-text">
 | 
				
			||||||
          <div class="fee-text" [ngClass]="{'danger' : unbackedMonths.avg < 1, 'correct': unbackedMonths.avg >= 1}">
 | 
					          <div class="fee-text" [ngClass]="{'danger' : unbackedMonths.avg < 1, 'correct': unbackedMonths.avg >= 1}">
 | 
				
			||||||
            {{ unbackedMonths.avg.toFixed(5) }}
 | 
					            {{ (unbackedMonths.avg * 100).toFixed(3) }} %
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
<div class="echarts" echarts [initOpts]="ratioHistoryChartInitOptions" [options]="ratioHistoryChartOptions" (chartRendered)="rendered()"></div>
 | 
					 | 
				
			||||||
<div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
					 | 
				
			||||||
  <div class="spinner-border text-light"></div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
@ -1,6 +0,0 @@
 | 
				
			|||||||
.loadingGraphs {
 | 
					 | 
				
			||||||
  position: absolute;
 | 
					 | 
				
			||||||
  top: 50%;
 | 
					 | 
				
			||||||
  left: calc(50% - 16px);
 | 
					 | 
				
			||||||
  z-index: 100;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,195 +0,0 @@
 | 
				
			|||||||
import { Component, Inject, LOCALE_ID, ChangeDetectionStrategy, Input, OnChanges, OnInit } from '@angular/core';
 | 
					 | 
				
			||||||
import { formatDate, formatNumber } from '@angular/common';
 | 
					 | 
				
			||||||
import { EChartsOption } from '../../../graphs/echarts';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Component({
 | 
					 | 
				
			||||||
  selector: 'app-reserves-ratio-graph',
 | 
					 | 
				
			||||||
  templateUrl: './reserves-ratio-graph.component.html',
 | 
					 | 
				
			||||||
  styleUrls: ['./reserves-ratio-graph.component.scss'],
 | 
					 | 
				
			||||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
					 | 
				
			||||||
})
 | 
					 | 
				
			||||||
export class ReservesRatioGraphComponent implements OnInit, OnChanges {
 | 
					 | 
				
			||||||
  @Input() data: any;
 | 
					 | 
				
			||||||
  ratioHistoryChartOptions: EChartsOption;
 | 
					 | 
				
			||||||
  ratioSeries: number[] = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  height: number | string = '200';
 | 
					 | 
				
			||||||
  right: number | string = '10';
 | 
					 | 
				
			||||||
  top: number | string = '20';
 | 
					 | 
				
			||||||
  left: number | string = '50';
 | 
					 | 
				
			||||||
  template: ('widget' | 'advanced') = 'widget';
 | 
					 | 
				
			||||||
  isLoading = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ratioHistoryChartInitOptions = {
 | 
					 | 
				
			||||||
    renderer: 'svg'
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  constructor(
 | 
					 | 
				
			||||||
    @Inject(LOCALE_ID) private locale: string,
 | 
					 | 
				
			||||||
  ) { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnInit() {
 | 
					 | 
				
			||||||
    this.isLoading = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnChanges() {
 | 
					 | 
				
			||||||
    if (!this.data) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // Compute the ratio series: the ratio of the reserves to the pegs
 | 
					 | 
				
			||||||
    this.ratioSeries = this.data.liquidReserves.series.map((value: number, index: number) => value / this.data.liquidPegs.series[index]);
 | 
					 | 
				
			||||||
    // Truncate the ratio series and labels series to last 3 years
 | 
					 | 
				
			||||||
    this.ratioSeries = this.ratioSeries.slice(Math.max(this.ratioSeries.length - 36, 0));
 | 
					 | 
				
			||||||
    this.data.liquidPegs.labels = this.data.liquidPegs.labels.slice(Math.max(this.data.liquidPegs.labels.length - 36, 0));
 | 
					 | 
				
			||||||
    // Cut the values that are too high or too low
 | 
					 | 
				
			||||||
    this.ratioSeries = this.ratioSeries.map((value: number) => Math.min(Math.max(value, 0.995), 1.005));
 | 
					 | 
				
			||||||
    this.ratioHistoryChartOptions = this.createChartOptions(this.ratioSeries, this.data.liquidPegs.labels);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rendered() {
 | 
					 | 
				
			||||||
    if (!this.data) {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    this.isLoading = false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  createChartOptions(ratioSeries: number[], labels: string[]): EChartsOption {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      grid: {
 | 
					 | 
				
			||||||
        height: this.height,
 | 
					 | 
				
			||||||
        right: this.right,
 | 
					 | 
				
			||||||
        top: this.top,
 | 
					 | 
				
			||||||
        left: this.left,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      animation: false,
 | 
					 | 
				
			||||||
      dataZoom: [{
 | 
					 | 
				
			||||||
        type: 'inside',
 | 
					 | 
				
			||||||
        realtime: true,
 | 
					 | 
				
			||||||
        zoomOnMouseWheel: (this.template === 'advanced') ? true : false,
 | 
					 | 
				
			||||||
        maxSpan: 100,
 | 
					 | 
				
			||||||
        minSpan: 10,
 | 
					 | 
				
			||||||
      }, {
 | 
					 | 
				
			||||||
        show: (this.template === 'advanced') ? true : false,
 | 
					 | 
				
			||||||
        type: 'slider',
 | 
					 | 
				
			||||||
        brushSelect: false,
 | 
					 | 
				
			||||||
        realtime: true,
 | 
					 | 
				
			||||||
        selectedDataBackground: {
 | 
					 | 
				
			||||||
          lineStyle: {
 | 
					 | 
				
			||||||
            color: '#fff',
 | 
					 | 
				
			||||||
            opacity: 0.45,
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          areaStyle: {
 | 
					 | 
				
			||||||
            opacity: 0,
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }],
 | 
					 | 
				
			||||||
      tooltip: {
 | 
					 | 
				
			||||||
        trigger: 'axis',
 | 
					 | 
				
			||||||
        position: (pos, params, el, elRect, size) => {
 | 
					 | 
				
			||||||
          const obj = { top: -20 };
 | 
					 | 
				
			||||||
          obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 80;
 | 
					 | 
				
			||||||
          return obj;
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        extraCssText: `width: ${(this.template === 'widget') ? '125px' : '135px'};
 | 
					 | 
				
			||||||
                      background: transparent;
 | 
					 | 
				
			||||||
                      border: none;
 | 
					 | 
				
			||||||
                      box-shadow: none;`,
 | 
					 | 
				
			||||||
        axisPointer: {
 | 
					 | 
				
			||||||
          type: 'line',
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        formatter: (params: any) => {
 | 
					 | 
				
			||||||
          const colorSpan = (color: string) => `<span class="indicator" style="background-color: ${color};"></span>`;
 | 
					 | 
				
			||||||
          let itemFormatted = '<div class="title">' + params[0].axisValue + '</div>';
 | 
					 | 
				
			||||||
          const item = params[0];
 | 
					 | 
				
			||||||
          const formattedValue = formatNumber(item.value, this.locale, '1.5-5');
 | 
					 | 
				
			||||||
          const symbol = (item.value === 1.005) ? '≥ ' : (item.value === 0.995) ? '≤ ' : '';
 | 
					 | 
				
			||||||
          itemFormatted += `<div class="item">
 | 
					 | 
				
			||||||
            <div class="indicator-container">${colorSpan(item.color)}</div>
 | 
					 | 
				
			||||||
            <div style="margin-right: 5px"></div>
 | 
					 | 
				
			||||||
            <div class="value">${symbol}${formattedValue}</div>
 | 
					 | 
				
			||||||
          </div>`;
 | 
					 | 
				
			||||||
          return `<div class="tx-wrapper-tooltip-chart ${(this.template === 'advanced') ? 'tx-wrapper-tooltip-chart-advanced' : ''}">${itemFormatted}</div>`;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      xAxis: {
 | 
					 | 
				
			||||||
        type: 'category',
 | 
					 | 
				
			||||||
        axisLabel: {
 | 
					 | 
				
			||||||
          align: 'center',
 | 
					 | 
				
			||||||
          fontSize: 11,
 | 
					 | 
				
			||||||
          lineHeight: 12
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        boundaryGap: false,
 | 
					 | 
				
			||||||
        data: labels.map((value: any) => `${formatDate(value, 'MMM\ny', this.locale)}`),
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      yAxis: {
 | 
					 | 
				
			||||||
        type: 'value',
 | 
					 | 
				
			||||||
        axisLabel: {
 | 
					 | 
				
			||||||
          fontSize: 11,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        splitLine: {
 | 
					 | 
				
			||||||
          lineStyle: {
 | 
					 | 
				
			||||||
            type: 'dotted',
 | 
					 | 
				
			||||||
            color: '#ffffff66',
 | 
					 | 
				
			||||||
            opacity: 0.25,
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        min: 0.995,
 | 
					 | 
				
			||||||
        max: 1.005,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      series: [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          data: ratioSeries,
 | 
					 | 
				
			||||||
          name: '',
 | 
					 | 
				
			||||||
          type: 'line',
 | 
					 | 
				
			||||||
          smooth: true,
 | 
					 | 
				
			||||||
          showSymbol: false,
 | 
					 | 
				
			||||||
          lineStyle: {
 | 
					 | 
				
			||||||
            width: 3,
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          markLine: {
 | 
					 | 
				
			||||||
            silent: true,
 | 
					 | 
				
			||||||
            symbol: 'none',
 | 
					 | 
				
			||||||
            lineStyle: {
 | 
					 | 
				
			||||||
              color: '#fff',
 | 
					 | 
				
			||||||
              opacity: 1,
 | 
					 | 
				
			||||||
              width: 1,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            data: [{
 | 
					 | 
				
			||||||
              yAxis: 1,
 | 
					 | 
				
			||||||
              label: {
 | 
					 | 
				
			||||||
                show: false,
 | 
					 | 
				
			||||||
                color: '#ffffff',
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }],
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      visualMap: {
 | 
					 | 
				
			||||||
        show: false,
 | 
					 | 
				
			||||||
        top: 50,
 | 
					 | 
				
			||||||
        right: 10,
 | 
					 | 
				
			||||||
        pieces: [{
 | 
					 | 
				
			||||||
          gt: 0,
 | 
					 | 
				
			||||||
          lte: 0.999,
 | 
					 | 
				
			||||||
          color: '#D81B60'
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          gt: 0.999,
 | 
					 | 
				
			||||||
          lte: 1.001,
 | 
					 | 
				
			||||||
          color: '#FDD835'
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          gt: 1.001,
 | 
					 | 
				
			||||||
          lte: 2,
 | 
					 | 
				
			||||||
          color: '#7CB342'
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        outOfRange: {
 | 
					 | 
				
			||||||
          color: '#999'
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Component, ChangeDetectionStrategy, Input, OnChanges, OnInit } from '@angular/core';
 | 
					import { Component, ChangeDetectionStrategy, Input, OnChanges, OnInit, HostListener } from '@angular/core';
 | 
				
			||||||
import { EChartsOption } from '../../../graphs/echarts';
 | 
					import { EChartsOption } from '../../../graphs/echarts';
 | 
				
			||||||
import { CurrentPegs } from '../../../interfaces/node-api.interface';
 | 
					import { CurrentPegs } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -32,6 +32,10 @@ export class ReservesRatioComponent implements OnInit, OnChanges {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnChanges() {
 | 
					  ngOnChanges() {
 | 
				
			||||||
 | 
					    this.updateChartOptions();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  updateChartOptions() {
 | 
				
			||||||
    if (!this.currentPeg || !this.currentReserves || this.currentPeg.amount === '0') {
 | 
					    if (!this.currentPeg || !this.currentReserves || this.currentPeg.amount === '0') {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -46,13 +50,43 @@ export class ReservesRatioComponent implements OnInit, OnChanges {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  createChartOptions(currentPeg: CurrentPegs, currentReserves: CurrentPegs): EChartsOption {
 | 
					  createChartOptions(currentPeg: CurrentPegs, currentReserves: CurrentPegs): EChartsOption {
 | 
				
			||||||
 | 
					    const value = parseFloat(currentReserves.amount) / parseFloat(currentPeg.amount);
 | 
				
			||||||
 | 
					    const hideMaxAxisLabels = value >= 1.001;
 | 
				
			||||||
 | 
					    const hideMinAxisLabels = value <= 0.999;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let axisFontSize = 14;
 | 
				
			||||||
 | 
					    let pointerLength = '50%';
 | 
				
			||||||
 | 
					    let pointerWidth = 16;
 | 
				
			||||||
 | 
					    let offsetCenter = ['0%', '-22%'];
 | 
				
			||||||
 | 
					    if (window.innerWidth >= 992) {
 | 
				
			||||||
 | 
					      axisFontSize = 14;
 | 
				
			||||||
 | 
					      pointerLength = '50%';
 | 
				
			||||||
 | 
					      pointerWidth = 16;
 | 
				
			||||||
 | 
					      offsetCenter = value >= 1.0007 || value <= 0.9993 ? ['0%', '-30%'] : ['0%', '-22%'];
 | 
				
			||||||
 | 
					    } else if (window.innerWidth >= 768) {
 | 
				
			||||||
 | 
					      axisFontSize = 10;
 | 
				
			||||||
 | 
					      pointerLength = '35%';
 | 
				
			||||||
 | 
					      pointerWidth = 12;
 | 
				
			||||||
 | 
					      offsetCenter = value >= 1.0007 || value <= 0.9993 ? ['0%', '-37%'] : ['0%', '-27%'];
 | 
				
			||||||
 | 
					    } else if (window.innerWidth >= 450) {
 | 
				
			||||||
 | 
					      axisFontSize = 14;
 | 
				
			||||||
 | 
					      pointerLength = '45%';
 | 
				
			||||||
 | 
					      pointerWidth = 14;
 | 
				
			||||||
 | 
					      offsetCenter = value >= 1.0007 || value <= 0.9993 ? ['0%', '-32%'] : ['0%', '-22%'];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      axisFontSize = 10;
 | 
				
			||||||
 | 
					      pointerLength = '35%';
 | 
				
			||||||
 | 
					      pointerWidth = 12;
 | 
				
			||||||
 | 
					      offsetCenter = value >= 1.0007 || value <= 0.9993 ? ['0%', '-37%'] : ['0%', '-27%'];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      series: [
 | 
					      series: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          type: 'gauge',
 | 
					          type: 'gauge',
 | 
				
			||||||
          startAngle: 180,
 | 
					          startAngle: 180,
 | 
				
			||||||
          endAngle: 0,
 | 
					          endAngle: 0,
 | 
				
			||||||
          center: ['50%', '70%'],
 | 
					          center: ['50%', '75%'],
 | 
				
			||||||
          radius: '100%',
 | 
					          radius: '100%',
 | 
				
			||||||
          min: 0.999,
 | 
					          min: 0.999,
 | 
				
			||||||
          max: 1.001,
 | 
					          max: 1.001,
 | 
				
			||||||
@ -69,12 +103,22 @@ export class ReservesRatioComponent implements OnInit, OnChanges {
 | 
				
			|||||||
          axisLabel: {
 | 
					          axisLabel: {
 | 
				
			||||||
            color: 'inherit',        
 | 
					            color: 'inherit',        
 | 
				
			||||||
            fontFamily: 'inherit',  
 | 
					            fontFamily: 'inherit',  
 | 
				
			||||||
 | 
					            fontSize: axisFontSize,  
 | 
				
			||||||
 | 
					            formatter: function (value) {
 | 
				
			||||||
 | 
					              if (value === 0.999) {
 | 
				
			||||||
 | 
					                return hideMinAxisLabels ? '' : '99.9%';
 | 
				
			||||||
 | 
					              } else if (value === 1.001) {
 | 
				
			||||||
 | 
					                return hideMaxAxisLabels ? '' : '100.1%';
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                return '100%';
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          pointer: {
 | 
					          pointer: {
 | 
				
			||||||
            icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
 | 
					            icon: 'path://M2090.36389,615.30999 L2090.36389,615.30999 C2091.48372,615.30999 2092.40383,616.194028 2092.44859,617.312956 L2096.90698,728.755929 C2097.05155,732.369577 2094.2393,735.416212 2090.62566,735.56078 C2090.53845,735.564269 2090.45117,735.566014 2090.36389,735.566014 L2090.36389,735.566014 C2086.74736,735.566014 2083.81557,732.63423 2083.81557,729.017692 C2083.81557,728.930412 2083.81732,728.84314 2083.82081,728.755929 L2088.2792,617.312956 C2088.32396,616.194028 2089.24407,615.30999 2090.36389,615.30999 Z',
 | 
				
			||||||
            length: '50%',
 | 
					            length: pointerLength,
 | 
				
			||||||
            width: 16,
 | 
					            width: pointerWidth,
 | 
				
			||||||
            offsetCenter: [0, '-27%'],
 | 
					            offsetCenter: offsetCenter,
 | 
				
			||||||
            itemStyle: {
 | 
					            itemStyle: {
 | 
				
			||||||
              color: 'auto'
 | 
					              color: 'auto'
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -95,7 +139,7 @@ export class ReservesRatioComponent implements OnInit, OnChanges {
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
          title: {
 | 
					          title: {
 | 
				
			||||||
            show: true,
 | 
					            show: true,
 | 
				
			||||||
            offsetCenter: [0, '-117.5%'],
 | 
					            offsetCenter: [0, '-127%'],
 | 
				
			||||||
            fontSize: 18,
 | 
					            fontSize: 18,
 | 
				
			||||||
            color: '#4a68b9',
 | 
					            color: '#4a68b9',
 | 
				
			||||||
            fontFamily: 'inherit',
 | 
					            fontFamily: 'inherit',
 | 
				
			||||||
@ -108,19 +152,24 @@ export class ReservesRatioComponent implements OnInit, OnChanges {
 | 
				
			|||||||
            fontFamily: 'inherit',
 | 
					            fontFamily: 'inherit',
 | 
				
			||||||
            fontWeight: 500,
 | 
					            fontWeight: 500,
 | 
				
			||||||
            formatter: function (value) {
 | 
					            formatter: function (value) {
 | 
				
			||||||
              return (value).toFixed(5);
 | 
					              return (value * 100).toFixed(3) + '%';
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            color: 'inherit'
 | 
					            color: 'inherit'
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          data: [
 | 
					          data: [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
              value: parseFloat(currentReserves.amount) / parseFloat(currentPeg.amount),
 | 
					              value: value,
 | 
				
			||||||
              name: 'Peg-O-Meter'
 | 
					              name: 'Assets vs Liabilities'
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          ]
 | 
					          ]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @HostListener('window:resize', ['$event'])
 | 
				
			||||||
 | 
					  onResize(): void {
 | 
				
			||||||
 | 
					    this.updateChartOptions();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,44 +1,29 @@
 | 
				
			|||||||
<div *ngIf="(currentPeg$ | async) as currentPeg; else loadingData">
 | 
					<div class="fee-estimation-container">
 | 
				
			||||||
  <div *ngIf="(currentReserves$ | async) as currentReserves; else loadingData">
 | 
					 | 
				
			||||||
    <div class="fee-estimation-container">
 | 
					 | 
				
			||||||
  <div class="item">
 | 
					  <div class="item">
 | 
				
			||||||
    <h5 class="card-title" i18n="dashboard.lbtc-pegs-in-circulation">L-BTC in circulation</h5>
 | 
					    <h5 class="card-title" i18n="dashboard.lbtc-pegs-in-circulation">L-BTC in circulation</h5>
 | 
				
			||||||
        <div class="card-text">
 | 
					    <div *ngIf="(currentPeg$ | async) as currentPeg; else loadingData" class="card-text">
 | 
				
			||||||
      <div class="fee-text">{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} <span>L-BTC</span></div>
 | 
					      <div class="fee-text">{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} <span>L-BTC</span></div>
 | 
				
			||||||
      <span class="fiat">
 | 
					      <span class="fiat">
 | 
				
			||||||
            <span>As of block <a [routerLink]="['/block', currentPeg.hash]">{{ currentPeg.lastBlockUpdate }}</a></span>
 | 
					        <span><ng-container i18n="shared.as-of-block">As of block</ng-container> <a [routerLink]="['/block', currentPeg.hash]">{{ currentPeg.lastBlockUpdate }}</a></span>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="item">
 | 
					  <div class="item">
 | 
				
			||||||
        <h5 class="card-title" i18n="dashboard.btc-reserves">BTC Reserves</h5>
 | 
					    <h5 class="card-title" i18n="dashboard.btc-holdings">BTC Holdings</h5>
 | 
				
			||||||
        <div class="card-text">
 | 
					    <div *ngIf="(currentReserves$ | async) as currentReserves; else loadingData" class="card-text">
 | 
				
			||||||
      <div class="fee-text">{{ (+currentReserves.amount) / 100000000 | number: '1.2-2' }} <span style="color: #b86d12;">BTC</span></div>
 | 
					      <div class="fee-text">{{ (+currentReserves.amount) / 100000000 | number: '1.2-2' }} <span style="color: #b86d12;">BTC</span></div>
 | 
				
			||||||
      <span class="fiat">
 | 
					      <span class="fiat">
 | 
				
			||||||
            <span>As of block <a href="{{ env.MEMPOOL_WEBSITE_URL + '/block/' + currentReserves.hash }}" target="_blank" style="color:#b86d12">{{ currentReserves.lastBlockUpdate }}</a></span>
 | 
					        <span><ng-container i18n="shared.as-of-block">As of block</ng-container> <a href="{{ env.MEMPOOL_WEBSITE_URL + '/block/' + currentReserves.hash }}" target="_blank" style="color:#b86d12">{{ currentReserves.lastBlockUpdate }}</a></span>
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #loadingData>
 | 
					<ng-template #loadingData>
 | 
				
			||||||
  <div class="fee-estimation-container loading-container">
 | 
					 | 
				
			||||||
    <div class="item">
 | 
					 | 
				
			||||||
      <h5 class="card-title" i18n="dashboard.lbtc-pegs-in-circulation">L-BTC in circulation</h5>
 | 
					 | 
				
			||||||
  <div class="card-text">
 | 
					  <div class="card-text">
 | 
				
			||||||
    <div class="skeleton-loader"></div>
 | 
					    <div class="skeleton-loader"></div>
 | 
				
			||||||
    <div class="skeleton-loader"></div>
 | 
					    <div class="skeleton-loader"></div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="item">
 | 
					 | 
				
			||||||
      <h5 class="card-title" i18n="dashboard.btc-reserves">BTC Reserves</h5>
 | 
					 | 
				
			||||||
      <div class="card-text">
 | 
					 | 
				
			||||||
        <div class="skeleton-loader"></div>
 | 
					 | 
				
			||||||
        <div class="skeleton-loader"></div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -41,6 +41,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    .fee-text{
 | 
					    .fee-text{
 | 
				
			||||||
      border-bottom: 1px solid #ffffff1c;
 | 
					      border-bottom: 1px solid #ffffff1c;
 | 
				
			||||||
 | 
					      color: #ffffff;
 | 
				
			||||||
      width: fit-content;
 | 
					      width: fit-content;
 | 
				
			||||||
      margin: auto;
 | 
					      margin: auto;
 | 
				
			||||||
      line-height: 1.45;
 | 
					      line-height: 1.45;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<div class="container-xl dashboard-container">
 | 
					<div class="container-xl dashboard-container" *ngIf="(network$ | async) !== 'liquid'; else liquidDashboard">
 | 
				
			||||||
  <div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
 | 
					  <div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
 | 
				
			||||||
    <ng-container *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
 | 
					    <ng-container *ngIf="(network$ | async) !== 'liquidtestnet'">
 | 
				
			||||||
      <div class="col card-wrapper">
 | 
					      <div class="col card-wrapper">
 | 
				
			||||||
        <div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
 | 
					        <div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
 | 
				
			||||||
        <div class="card">
 | 
					        <div class="card">
 | 
				
			||||||
@ -17,7 +17,6 @@
 | 
				
			|||||||
    <div class="col">
 | 
					    <div class="col">
 | 
				
			||||||
      <div class="card graph-card">
 | 
					      <div class="card graph-card">
 | 
				
			||||||
        <div class="card-body pl-lg-3 pr-lg-3 pl-2 pr-2">
 | 
					        <div class="card-body pl-lg-3 pr-lg-3 pl-2 pr-2">
 | 
				
			||||||
          <ng-template [ngIf]="(network$ | async) !== 'liquid'" [ngIfElse]="liquidPegs">
 | 
					 | 
				
			||||||
          <a class="title-link mb-0" style="margin-top: -2px" href="" [routerLink]="['/mempool-block/0' | relativeUrl]">
 | 
					          <a class="title-link mb-0" style="margin-top: -2px" href="" [routerLink]="['/mempool-block/0' | relativeUrl]">
 | 
				
			||||||
            <h5 class="card-title d-inline"><span i18n="dashboard.mempool-goggles">Mempool Goggles</span>: {{ goggleCycle[goggleIndex].name }}</h5>
 | 
					            <h5 class="card-title d-inline"><span i18n="dashboard.mempool-goggles">Mempool Goggles</span>: {{ goggleCycle[goggleIndex].name }}</h5>
 | 
				
			||||||
            <span> </span>
 | 
					            <span> </span>
 | 
				
			||||||
@ -38,14 +37,6 @@
 | 
				
			|||||||
              [filterMode]="goggleMode"
 | 
					              [filterMode]="goggleMode"
 | 
				
			||||||
            ></app-mempool-block-overview>
 | 
					            ></app-mempool-block-overview>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          </ng-template>
 | 
					 | 
				
			||||||
          <ng-template #liquidPegs>
 | 
					 | 
				
			||||||
            <div style="padding-left: 1.25rem;">
 | 
					 | 
				
			||||||
              <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? lbtcPegs : mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					 | 
				
			||||||
              <hr>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <app-lbtc-pegs-graph [data]="fullHistory$ | async" [height]="lbtcPegGraphHeight"></app-lbtc-pegs-graph>
 | 
					 | 
				
			||||||
          </ng-template>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -53,7 +44,6 @@
 | 
				
			|||||||
      <div class="card graph-card">
 | 
					      <div class="card graph-card">
 | 
				
			||||||
        <div class="card-body">
 | 
					        <div class="card-body">
 | 
				
			||||||
          <ng-container *ngTemplateOutlet="mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					          <ng-container *ngTemplateOutlet="mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
				
			||||||
          <ng-container *ngIf="stateService.network !== 'liquid'">
 | 
					 | 
				
			||||||
            <h5 class="card-title mt-3" i18n="dashboard.incoming-transactions">Incoming Transactions</h5>
 | 
					            <h5 class="card-title mt-3" i18n="dashboard.incoming-transactions">Incoming Transactions</h5>
 | 
				
			||||||
            <div class="mempool-graph" *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
					            <div class="mempool-graph" *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
				
			||||||
              <app-incoming-transactions-graph
 | 
					              <app-incoming-transactions-graph
 | 
				
			||||||
@ -64,30 +54,11 @@
 | 
				
			|||||||
                [windowPreferenceOverride]="'2h'"
 | 
					                [windowPreferenceOverride]="'2h'"
 | 
				
			||||||
                ></app-incoming-transactions-graph>
 | 
					                ></app-incoming-transactions-graph>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </ng-container>
 | 
					 | 
				
			||||||
          <div class="mempool-graph" *ngIf="stateService.network === 'liquid'">
 | 
					 | 
				
			||||||
            <hr>
 | 
					 | 
				
			||||||
            <table class="table table-borderless table-striped" *ngIf="(featuredAssets$ | async) as featuredAssets else loadingAssetsTable">
 | 
					 | 
				
			||||||
              <tbody>
 | 
					 | 
				
			||||||
                <tr *ngFor="let group of featuredAssets">
 | 
					 | 
				
			||||||
                  <td class="asset-icon">
 | 
					 | 
				
			||||||
                    <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">
 | 
					 | 
				
			||||||
                      <img class="assetIcon" [src]="'/api/v1/asset/' + group.asset + '/icon'">
 | 
					 | 
				
			||||||
                    </a>
 | 
					 | 
				
			||||||
                  </td>
 | 
					 | 
				
			||||||
                  <td class="asset-title">
 | 
					 | 
				
			||||||
                    <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">{{ group.name }}</a>
 | 
					 | 
				
			||||||
                  </td>
 | 
					 | 
				
			||||||
                  <td class="circulating-amount"><app-asset-circulation [assetId]="group.asset"></app-asset-circulation></td>
 | 
					 | 
				
			||||||
                </tr>
 | 
					 | 
				
			||||||
              </tbody>
 | 
					 | 
				
			||||||
            </table>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="col" style="max-height: 410px">
 | 
					    <div class="col" style="max-height: 410px">
 | 
				
			||||||
      <div class="card" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else latestBlocks">
 | 
					      <div class="card" *ngIf="(network$ | async) !== 'liquidtestnet'; else latestBlocks">
 | 
				
			||||||
        <div class="card-body">
 | 
					        <div class="card-body">
 | 
				
			||||||
          <a class="title-link" href="" [routerLink]="['/rbf' | relativeUrl]">
 | 
					          <a class="title-link" href="" [routerLink]="['/rbf' | relativeUrl]">
 | 
				
			||||||
            <h5 class="card-title d-inline" i18n="dashboard.recent-rbf-replacements">Recent Replacements</h5>
 | 
					            <h5 class="card-title d-inline" i18n="dashboard.recent-rbf-replacements">Recent Replacements</h5>
 | 
				
			||||||
@ -171,7 +142,7 @@
 | 
				
			|||||||
                    <app-truncate [text]="transaction.txid" [lastChars]="5"></app-truncate>
 | 
					                    <app-truncate [text]="transaction.txid" [lastChars]="5"></app-truncate>
 | 
				
			||||||
                  </a>
 | 
					                  </a>
 | 
				
			||||||
                </td>
 | 
					                </td>
 | 
				
			||||||
                <td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
 | 
					                <td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
 | 
				
			||||||
                <td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
 | 
					                <td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
 | 
				
			||||||
                <td class="table-cell-fees"><app-fee-rate [fee]="transaction.fee" [weight]="transaction.vsize * 4"></app-fee-rate></td>
 | 
					                <td class="table-cell-fees"><app-fee-rate [fee]="transaction.fee" [weight]="transaction.vsize * 4"></app-fee-rate></td>
 | 
				
			||||||
              </tr>
 | 
					              </tr>
 | 
				
			||||||
@ -184,25 +155,50 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #loadingAssetsTable>
 | 
					<ng-template #liquidDashboard>
 | 
				
			||||||
  <table class="table table-borderless table-striped asset-table">
 | 
					  <div class="container-xl dashboard-container" *ngIf="(auditStatus$ | async)?.isAuditSynced; else auditInProgress">
 | 
				
			||||||
    <tbody>
 | 
					
 | 
				
			||||||
      <tr *ngFor="let i of getArrayFromNumber(this.nbFeaturedAssets)">
 | 
					    <div class="row row-cols-1 row-cols-md-2">
 | 
				
			||||||
        <td class="asset-icon">
 | 
					  
 | 
				
			||||||
          <div class="skeleton-loader skeleton-loader-transactions"></div>
 | 
					      <div class="col">
 | 
				
			||||||
        </td>
 | 
					        <div class="card-liquid card">
 | 
				
			||||||
        <td class="asset-title">
 | 
					          <div class="card-title card-title-liquid">
 | 
				
			||||||
          <div class="skeleton-loader skeleton-loader-transactions"></div>
 | 
					            <app-reserves-supply-stats [currentPeg$]="currentPeg$" [currentReserves$]="currentReserves$"></app-reserves-supply-stats>
 | 
				
			||||||
        </td>
 | 
					          </div>
 | 
				
			||||||
        <td class="asset-title d-none d-md-table-cell">
 | 
					          <div class="card-body pl-0" style="padding-top: 10px;">
 | 
				
			||||||
          <div class="skeleton-loader skeleton-loader-transactions"></div>
 | 
					            <app-lbtc-pegs-graph [data]="fullHistory$ | async" [height]="lbtcPegGraphHeight"></app-lbtc-pegs-graph>
 | 
				
			||||||
        </td>
 | 
					          </div>
 | 
				
			||||||
        <td class="asset-title">
 | 
					        </div>
 | 
				
			||||||
          <div class="skeleton-loader skeleton-loader-transactions"></div>
 | 
					      </div>
 | 
				
			||||||
        </td>
 | 
					  
 | 
				
			||||||
      </tr>
 | 
					      <div class="col" style="margin-bottom: 1.47rem">
 | 
				
			||||||
    </tbody>
 | 
					        <div class="card-liquid card"> 
 | 
				
			||||||
  </table>
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-reserves-ratio-stats [fullHistory$]="fullHistory$"></app-reserves-ratio-stats>
 | 
				
			||||||
 | 
					            <app-reserves-ratio [currentPeg]="currentPeg$ | async" [currentReserves]="currentReserves$ | async"></app-reserves-ratio>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="col">
 | 
				
			||||||
 | 
					        <div class="card card-liquid smaller">
 | 
				
			||||||
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-recent-pegs-stats [pegsVolume$]="pegsVolume$"></app-recent-pegs-stats>
 | 
				
			||||||
 | 
					            <app-recent-pegs-list [recentPegsList$]="recentPegsList$" [widget]="true"></app-recent-pegs-list>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="col" style="margin-bottom: 1.47rem">
 | 
				
			||||||
 | 
					        <div class="card-liquid card smaller">
 | 
				
			||||||
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-federation-addresses-stats [federationAddressesNumber$]="federationAddressesNumber$" [federationUtxosNumber$]="federationUtxosNumber$"></app-federation-addresses-stats>
 | 
				
			||||||
 | 
					            <app-federation-addresses-list [federationAddresses$]="federationAddresses$" [widget]="true"></app-federation-addresses-list>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #replacementsSkeleton>
 | 
					<ng-template #replacementsSkeleton>
 | 
				
			||||||
@ -283,21 +279,56 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #lbtcPegs let-mempoolInfoData>
 | 
					<ng-template #loadingSkeletonLiquid>
 | 
				
			||||||
  <div class="mempool-info-data">
 | 
					  <div class="container-xl dashboard-container">
 | 
				
			||||||
    <div class="item">
 | 
					
 | 
				
			||||||
      <h5 class="card-title" i18n="dashboard.lbtc-pegs-in-circulation">L-BTC in circulation</h5>
 | 
					    <div class="row row-cols-1 row-cols-md-2">
 | 
				
			||||||
      <ng-container *ngIf="(currentPeg$ | async) as currentPeg; else loadingTransactions">
 | 
					  
 | 
				
			||||||
        <p i18n-ngbTooltip="liquid.last-elements-audit-block" [ngbTooltip]="'L-BTC supply last updated at Liquid block ' + (currentPeg.lastBlockUpdate)" placement="top" class="card-text">{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} <span>L-BTC</span></p>
 | 
					      <div class="col">
 | 
				
			||||||
      </ng-container>
 | 
					        <div class="card-liquid card">
 | 
				
			||||||
 | 
					          <div class="card-title card-title-liquid">
 | 
				
			||||||
 | 
					            <app-reserves-supply-stats></app-reserves-supply-stats>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="card-body pl-0" style="padding-top: 10px;">
 | 
				
			||||||
 | 
					            <app-lbtc-pegs-graph [height]="lbtcPegGraphHeight"></app-lbtc-pegs-graph>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      <div class="col" style="margin-bottom: 1.47rem">
 | 
				
			||||||
 | 
					        <div class="card-liquid card"> 
 | 
				
			||||||
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-reserves-ratio-stats></app-reserves-ratio-stats>
 | 
				
			||||||
 | 
					            <app-reserves-ratio></app-reserves-ratio>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="col">
 | 
				
			||||||
 | 
					        <div class="card card-liquid smaller">
 | 
				
			||||||
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-recent-pegs-stats></app-recent-pegs-stats>
 | 
				
			||||||
 | 
					            <app-recent-pegs-list [widget]="true"></app-recent-pegs-list>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="col" style="margin-bottom: 1.47rem">
 | 
				
			||||||
 | 
					        <div class="card-liquid card smaller">
 | 
				
			||||||
 | 
					          <div class="card-body">
 | 
				
			||||||
 | 
					            <app-federation-addresses-stats></app-federation-addresses-stats>
 | 
				
			||||||
 | 
					            <app-federation-addresses-list [widget]="true"></app-federation-addresses-list>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    <div class="item">
 | 
					 | 
				
			||||||
      <a class="title-link" [routerLink]="['/audit' | relativeUrl]">
 | 
					 | 
				
			||||||
        <h5 class="card-title"><ng-container i18n="dashboard.btc-reserves">BTC Reserves</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
					 | 
				
			||||||
      </a>
 | 
					 | 
				
			||||||
      <ng-container *ngIf="(currentReserves$ | async) as currentReserves; else loadingTransactions">
 | 
					 | 
				
			||||||
        <p i18n-ngbTooltip="liquid.last-bitcoin-audit-block" [ngbTooltip]="'BTC reserves last updated at Bitcoin block ' + (currentReserves.lastBlockUpdate)" placement="top" class="card-text">{{ +(currentReserves.amount) / 100000000 | number: '1.2-2' }} <span class="bitcoin-color">BTC</span></p>
 | 
					 | 
				
			||||||
      </ng-container>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<ng-template #auditInProgress>
 | 
				
			||||||
 | 
					  <ng-container *ngIf="(auditStatus$ | async) as auditStatus; else loadingSkeletonLiquid">
 | 
				
			||||||
 | 
					    <div class="in-progress-message" *ngIf="auditStatus.lastBlockAudit && auditStatus.bitcoinHeaders; else loadingSkeletonLiquid">
 | 
				
			||||||
 | 
					      <span i18n="liquid.audit-in-progress">Audit in progress: Bitcoin block height #{{ auditStatus.lastBlockAudit }} / #{{ auditStatus.bitcoinHeaders }}</span>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </ng-container>
 | 
				
			||||||
 | 
					</ng-template>
 | 
				
			||||||
@ -59,6 +59,10 @@
 | 
				
			|||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: row;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  &.lbtc-pegs-stats { 
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: row;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  h5 {
 | 
					  h5 {
 | 
				
			||||||
    margin-bottom: 10px;
 | 
					    margin-bottom: 10px;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -409,3 +413,27 @@
 | 
				
			|||||||
  margin-top: 5px;
 | 
					  margin-top: 5px;
 | 
				
			||||||
  margin-bottom: 6px;
 | 
					  margin-bottom: 6px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card-liquid {
 | 
				
			||||||
 | 
					  background-color: #1d1f31;
 | 
				
			||||||
 | 
					  height: 418px;
 | 
				
			||||||
 | 
					  @media (min-width: 992px) {
 | 
				
			||||||
 | 
					    height: 512px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  &.smaller {
 | 
				
			||||||
 | 
					    height: 408px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card-title-liquid {
 | 
				
			||||||
 | 
					  padding-top: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.in-progress-message {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  color: #ffffff91;
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  padding-bottom: 3px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { AfterViewInit, ChangeDetectionStrategy, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
 | 
					import { AfterViewInit, ChangeDetectionStrategy, Component, HostListener, OnDestroy, OnInit } from '@angular/core';
 | 
				
			||||||
import { combineLatest, EMPTY, fromEvent, merge, Observable, of, Subject, Subscription, timer } from 'rxjs';
 | 
					import { combineLatest, EMPTY, fromEvent, interval, merge, Observable, of, Subject, Subscription, timer } from 'rxjs';
 | 
				
			||||||
import { catchError, delayWhen, distinctUntilChanged, filter, map, scan, share, shareReplay, startWith, switchMap, takeUntil, tap, throttleTime } from 'rxjs/operators';
 | 
					import { catchError, delayWhen, distinctUntilChanged, filter, map, scan, share, shareReplay, startWith, switchMap, takeUntil, tap, throttleTime } from 'rxjs/operators';
 | 
				
			||||||
import { AuditStatus, BlockExtended, CurrentPegs, OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
					import { AuditStatus, BlockExtended, CurrentPegs, FederationAddress, OptimizedMempoolStats, PegsVolume, RecentPeg } from '../interfaces/node-api.interface';
 | 
				
			||||||
import { MempoolInfo, TransactionStripped, ReplacementInfo } from '../interfaces/websocket.interface';
 | 
					import { MempoolInfo, TransactionStripped, ReplacementInfo } from '../interfaces/websocket.interface';
 | 
				
			||||||
import { ApiService } from '../services/api.service';
 | 
					import { ApiService } from '../services/api.service';
 | 
				
			||||||
import { StateService } from '../services/state.service';
 | 
					import { StateService } from '../services/state.service';
 | 
				
			||||||
@ -33,8 +33,6 @@ interface MempoolStatsData {
 | 
				
			|||||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
					  changeDetection: ChangeDetectionStrategy.OnPush
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
					export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			||||||
  featuredAssets$: Observable<any>;
 | 
					 | 
				
			||||||
  nbFeaturedAssets = 6;
 | 
					 | 
				
			||||||
  network$: Observable<string>;
 | 
					  network$: Observable<string>;
 | 
				
			||||||
  mempoolBlocksData$: Observable<MempoolBlocksData>;
 | 
					  mempoolBlocksData$: Observable<MempoolBlocksData>;
 | 
				
			||||||
  mempoolInfoData$: Observable<MempoolInfoData>;
 | 
					  mempoolInfoData$: Observable<MempoolInfoData>;
 | 
				
			||||||
@ -54,6 +52,11 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
  auditUpdated$: Observable<boolean>;
 | 
					  auditUpdated$: Observable<boolean>;
 | 
				
			||||||
  liquidReservesMonth$: Observable<any>;
 | 
					  liquidReservesMonth$: Observable<any>;
 | 
				
			||||||
  currentReserves$: Observable<CurrentPegs>;
 | 
					  currentReserves$: Observable<CurrentPegs>;
 | 
				
			||||||
 | 
					  recentPegsList$: Observable<RecentPeg[]>;
 | 
				
			||||||
 | 
					  pegsVolume$: Observable<PegsVolume[]>;
 | 
				
			||||||
 | 
					  federationAddresses$: Observable<FederationAddress[]>;
 | 
				
			||||||
 | 
					  federationAddressesNumber$: Observable<number>;
 | 
				
			||||||
 | 
					  federationUtxosNumber$: Observable<number>;
 | 
				
			||||||
  fullHistory$: Observable<any>;
 | 
					  fullHistory$: Observable<any>;
 | 
				
			||||||
  isLoad: boolean = true;
 | 
					  isLoad: boolean = true;
 | 
				
			||||||
  filterSubscription: Subscription;
 | 
					  filterSubscription: Subscription;
 | 
				
			||||||
@ -184,26 +187,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const windowResize$ = fromEvent(window, 'resize').pipe(
 | 
					 | 
				
			||||||
      distinctUntilChanged(),
 | 
					 | 
				
			||||||
      startWith(null)
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
    this.featuredAssets$ = combineLatest([
 | 
					 | 
				
			||||||
      this.apiService.listFeaturedAssets$(),
 | 
					 | 
				
			||||||
      windowResize$
 | 
					 | 
				
			||||||
    ]).pipe(
 | 
					 | 
				
			||||||
        map(([featured, _]) => {
 | 
					 | 
				
			||||||
          const newArray = [];
 | 
					 | 
				
			||||||
          for (const feature of featured) {
 | 
					 | 
				
			||||||
            if (feature.ticker !== 'L-BTC' && feature.asset) {
 | 
					 | 
				
			||||||
              newArray.push(feature);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          return newArray.slice(0, this.nbFeaturedAssets);
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.transactions$ = this.stateService.transactions$
 | 
					    this.transactions$ = this.stateService.transactions$
 | 
				
			||||||
      .pipe(
 | 
					      .pipe(
 | 
				
			||||||
        scan((acc, tx) => {
 | 
					        scan((acc, tx) => {
 | 
				
			||||||
@ -269,7 +252,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
        share(),
 | 
					        share(),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
 | 
					    if (this.stateService.network === 'liquid') {
 | 
				
			||||||
      this.auditStatus$ = this.stateService.blocks$.pipe(
 | 
					      this.auditStatus$ = this.stateService.blocks$.pipe(
 | 
				
			||||||
        takeUntil(this.destroy$),
 | 
					        takeUntil(this.destroy$),
 | 
				
			||||||
        throttleTime(40000),
 | 
					        throttleTime(40000),
 | 
				
			||||||
@ -279,22 +262,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
        shareReplay(1)
 | 
					        shareReplay(1)
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ////////// Pegs historical data //////////
 | 
					 | 
				
			||||||
      this.liquidPegsMonth$ = this.auditStatus$.pipe(
 | 
					 | 
				
			||||||
        throttleTime(60 * 60 * 1000),
 | 
					 | 
				
			||||||
        switchMap(() => this.apiService.listLiquidPegsMonth$()),
 | 
					 | 
				
			||||||
        map((pegs) => {
 | 
					 | 
				
			||||||
          const labels = pegs.map(stats => stats.date);
 | 
					 | 
				
			||||||
          const series = pegs.map(stats => parseFloat(stats.amount) / 100000000);
 | 
					 | 
				
			||||||
          series.reduce((prev, curr, i) => series[i] = prev + curr, 0);
 | 
					 | 
				
			||||||
          return {
 | 
					 | 
				
			||||||
            series,
 | 
					 | 
				
			||||||
            labels
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        share(),
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this.currentPeg$ = this.auditStatus$.pipe(
 | 
					      this.currentPeg$ = this.auditStatus$.pipe(
 | 
				
			||||||
        switchMap(_ =>
 | 
					        switchMap(_ =>
 | 
				
			||||||
          this.apiService.liquidPegs$().pipe(
 | 
					          this.apiService.liquidPegs$().pipe(
 | 
				
			||||||
@ -307,7 +274,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ////////// BTC Reserves historical data //////////
 | 
					 | 
				
			||||||
      this.auditUpdated$ = combineLatest([
 | 
					      this.auditUpdated$ = combineLatest([
 | 
				
			||||||
        this.auditStatus$,
 | 
					        this.auditStatus$,
 | 
				
			||||||
        this.currentPeg$
 | 
					        this.currentPeg$
 | 
				
			||||||
@ -322,21 +288,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
          const amountCheck = currentPegAmount !== this.lastPegAmount;
 | 
					          const amountCheck = currentPegAmount !== this.lastPegAmount;
 | 
				
			||||||
          this.lastPegAmount = currentPegAmount;
 | 
					          this.lastPegAmount = currentPegAmount;
 | 
				
			||||||
          return of(blockAuditCheck || amountCheck);
 | 
					          return of(blockAuditCheck || amountCheck);
 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this.liquidReservesMonth$ = this.auditStatus$.pipe(
 | 
					 | 
				
			||||||
        throttleTime(60 * 60 * 1000),
 | 
					 | 
				
			||||||
        switchMap((auditStatus) => {
 | 
					 | 
				
			||||||
          return auditStatus.isAuditSynced ? this.apiService.listLiquidReservesMonth$() : EMPTY;
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        map(reserves => {
 | 
					 | 
				
			||||||
          const labels = reserves.map(stats => stats.date);
 | 
					 | 
				
			||||||
          const series = reserves.map(stats => parseFloat(stats.amount) / 100000000);
 | 
					 | 
				
			||||||
          return {
 | 
					 | 
				
			||||||
            series,
 | 
					 | 
				
			||||||
            labels
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
        }),
 | 
					        }),
 | 
				
			||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@ -355,7 +306,74 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
        share()
 | 
					        share()
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.fullHistory$ = combineLatest([this.liquidPegsMonth$, this.currentPeg$, this.liquidReservesMonth$.pipe(startWith(null)), this.currentReserves$.pipe(startWith(null))])
 | 
					      this.recentPegsList$ = this.auditUpdated$.pipe(
 | 
				
			||||||
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
 | 
					        throttleTime(40000),
 | 
				
			||||||
 | 
					        switchMap(_ => this.apiService.recentPegsList$()),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.pegsVolume$ = this.auditUpdated$.pipe(
 | 
				
			||||||
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
 | 
					        throttleTime(40000),
 | 
				
			||||||
 | 
					        switchMap(_ => this.apiService.pegsVolume$()),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.federationAddresses$ = this.auditUpdated$.pipe(
 | 
				
			||||||
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
 | 
					        throttleTime(40000),
 | 
				
			||||||
 | 
					        switchMap(_ => this.apiService.federationAddresses$()),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.federationAddressesNumber$ = this.auditUpdated$.pipe(
 | 
				
			||||||
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
 | 
					        throttleTime(40000),
 | 
				
			||||||
 | 
					        switchMap(_ => this.apiService.federationAddressesNumber$()),
 | 
				
			||||||
 | 
					        map(count => count.address_count),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.federationUtxosNumber$ = this.auditUpdated$.pipe(
 | 
				
			||||||
 | 
					        filter(auditUpdated => auditUpdated === true),
 | 
				
			||||||
 | 
					        throttleTime(40000),
 | 
				
			||||||
 | 
					        switchMap(_ => this.apiService.federationUtxosNumber$()),
 | 
				
			||||||
 | 
					        map(count => count.utxo_count),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.liquidPegsMonth$ = interval(60 * 60 * 1000)
 | 
				
			||||||
 | 
					        .pipe(
 | 
				
			||||||
 | 
					          startWith(0),
 | 
				
			||||||
 | 
					          switchMap(() => this.apiService.listLiquidPegsMonth$()),
 | 
				
			||||||
 | 
					          map((pegs) => {
 | 
				
			||||||
 | 
					            const labels = pegs.map(stats => stats.date);
 | 
				
			||||||
 | 
					            const series = pegs.map(stats => parseFloat(stats.amount) / 100000000);
 | 
				
			||||||
 | 
					            series.reduce((prev, curr, i) => series[i] = prev + curr, 0);
 | 
				
			||||||
 | 
					            return {
 | 
				
			||||||
 | 
					              series,
 | 
				
			||||||
 | 
					              labels
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					          share(),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.liquidReservesMonth$ = interval(60 * 60 * 1000).pipe(
 | 
				
			||||||
 | 
					        startWith(0),
 | 
				
			||||||
 | 
					        switchMap(() => this.apiService.listLiquidReservesMonth$()),
 | 
				
			||||||
 | 
					        map(reserves => {
 | 
				
			||||||
 | 
					          const labels = reserves.map(stats => stats.date);
 | 
				
			||||||
 | 
					          const series = reserves.map(stats => parseFloat(stats.amount) / 100000000);
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            series,
 | 
				
			||||||
 | 
					            labels
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        share()
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					      this.fullHistory$ = combineLatest([this.liquidPegsMonth$, this.currentPeg$, this.liquidReservesMonth$, this.currentReserves$])
 | 
				
			||||||
        .pipe(
 | 
					        .pipe(
 | 
				
			||||||
          map(([liquidPegs, currentPeg, liquidReserves, currentReserves]) => {
 | 
					          map(([liquidPegs, currentPeg, liquidReserves, currentReserves]) => {
 | 
				
			||||||
            liquidPegs.series[liquidPegs.series.length - 1] = parseFloat(currentPeg.amount) / 100000000;
 | 
					            liquidPegs.series[liquidPegs.series.length - 1] = parseFloat(currentPeg.amount) / 100000000;
 | 
				
			||||||
@ -415,17 +433,14 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit {
 | 
				
			|||||||
      this.incomingGraphHeight = 300;
 | 
					      this.incomingGraphHeight = 300;
 | 
				
			||||||
      this.goggleResolution = 82;
 | 
					      this.goggleResolution = 82;
 | 
				
			||||||
      this.lbtcPegGraphHeight = 320;
 | 
					      this.lbtcPegGraphHeight = 320;
 | 
				
			||||||
      this.nbFeaturedAssets = 6;
 | 
					 | 
				
			||||||
    } else if (window.innerWidth >= 768) {
 | 
					    } else if (window.innerWidth >= 768) {
 | 
				
			||||||
      this.incomingGraphHeight = 215;
 | 
					      this.incomingGraphHeight = 215;
 | 
				
			||||||
      this.goggleResolution = 80;
 | 
					      this.goggleResolution = 80;
 | 
				
			||||||
      this.lbtcPegGraphHeight = 230;
 | 
					      this.lbtcPegGraphHeight = 230;
 | 
				
			||||||
      this.nbFeaturedAssets = 4;
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.incomingGraphHeight = 180;
 | 
					      this.incomingGraphHeight = 180;
 | 
				
			||||||
      this.goggleResolution = 86;
 | 
					      this.goggleResolution = 86;
 | 
				
			||||||
      this.lbtcPegGraphHeight = 220;
 | 
					      this.lbtcPegGraphHeight = 220;
 | 
				
			||||||
      this.nbFeaturedAssets = 4;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,13 @@ import { FeeDistributionGraphComponent } from '../components/fee-distribution-gr
 | 
				
			|||||||
import { IncomingTransactionsGraphComponent } from '../components/incoming-transactions-graph/incoming-transactions-graph.component';
 | 
					import { IncomingTransactionsGraphComponent } from '../components/incoming-transactions-graph/incoming-transactions-graph.component';
 | 
				
			||||||
import { MempoolGraphComponent } from '../components/mempool-graph/mempool-graph.component';
 | 
					import { MempoolGraphComponent } from '../components/mempool-graph/mempool-graph.component';
 | 
				
			||||||
import { LbtcPegsGraphComponent } from '../components/lbtc-pegs-graph/lbtc-pegs-graph.component';
 | 
					import { LbtcPegsGraphComponent } from '../components/lbtc-pegs-graph/lbtc-pegs-graph.component';
 | 
				
			||||||
 | 
					import { ReservesSupplyStatsComponent } from '../components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component';
 | 
				
			||||||
 | 
					import { ReservesRatioStatsComponent } from '../components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component';
 | 
				
			||||||
 | 
					import { ReservesRatioComponent } from '../components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component';
 | 
				
			||||||
 | 
					import { RecentPegsStatsComponent } from '../components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component';
 | 
				
			||||||
 | 
					import { RecentPegsListComponent } from '../components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component';
 | 
				
			||||||
 | 
					import { FederationAddressesStatsComponent } from '../components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component';
 | 
				
			||||||
 | 
					import { FederationAddressesListComponent } from '../components/liquid-reserves-audit/federation-addresses-list/federation-addresses-list.component';
 | 
				
			||||||
import { GraphsComponent } from '../components/graphs/graphs.component';
 | 
					import { GraphsComponent } from '../components/graphs/graphs.component';
 | 
				
			||||||
import { StatisticsComponent } from '../components/statistics/statistics.component';
 | 
					import { StatisticsComponent } from '../components/statistics/statistics.component';
 | 
				
			||||||
import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component';
 | 
					import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component';
 | 
				
			||||||
@ -48,6 +55,13 @@ import { CommonModule } from '@angular/common';
 | 
				
			|||||||
    IncomingTransactionsGraphComponent,
 | 
					    IncomingTransactionsGraphComponent,
 | 
				
			||||||
    MempoolGraphComponent,
 | 
					    MempoolGraphComponent,
 | 
				
			||||||
    LbtcPegsGraphComponent,
 | 
					    LbtcPegsGraphComponent,
 | 
				
			||||||
 | 
					    ReservesSupplyStatsComponent,
 | 
				
			||||||
 | 
					    ReservesRatioStatsComponent,
 | 
				
			||||||
 | 
					    ReservesRatioComponent,
 | 
				
			||||||
 | 
					    RecentPegsStatsComponent,
 | 
				
			||||||
 | 
					    RecentPegsListComponent,
 | 
				
			||||||
 | 
					    FederationAddressesStatsComponent,
 | 
				
			||||||
 | 
					    FederationAddressesListComponent,
 | 
				
			||||||
    HashrateChartComponent,
 | 
					    HashrateChartComponent,
 | 
				
			||||||
    HashrateChartPoolsComponent,
 | 
					    HashrateChartPoolsComponent,
 | 
				
			||||||
    BlockHealthGraphComponent,
 | 
					    BlockHealthGraphComponent,
 | 
				
			||||||
 | 
				
			|||||||
@ -15,17 +15,10 @@ import { AssetsComponent } from '../components/assets/assets.component';
 | 
				
			|||||||
import { AssetsFeaturedComponent } from '../components/assets/assets-featured/assets-featured.component'
 | 
					import { AssetsFeaturedComponent } from '../components/assets/assets-featured/assets-featured.component'
 | 
				
			||||||
import { AssetComponent } from '../components/asset/asset.component';
 | 
					import { AssetComponent } from '../components/asset/asset.component';
 | 
				
			||||||
import { AssetsNavComponent } from '../components/assets/assets-nav/assets-nav.component';
 | 
					import { AssetsNavComponent } from '../components/assets/assets-nav/assets-nav.component';
 | 
				
			||||||
import { ReservesAuditDashboardComponent } from '../components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component';
 | 
					 | 
				
			||||||
import { ReservesSupplyStatsComponent } from '../components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component';
 | 
					 | 
				
			||||||
import { RecentPegsStatsComponent } from '../components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component';
 | 
					 | 
				
			||||||
import { RecentPegsListComponent } from '../components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component';
 | 
					import { RecentPegsListComponent } from '../components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component';
 | 
				
			||||||
import { FederationWalletComponent } from '../components/liquid-reserves-audit/federation-wallet/federation-wallet.component';
 | 
					import { FederationWalletComponent } from '../components/liquid-reserves-audit/federation-wallet/federation-wallet.component';
 | 
				
			||||||
import { FederationUtxosListComponent } from '../components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component';
 | 
					import { FederationUtxosListComponent } from '../components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component';
 | 
				
			||||||
import { FederationAddressesStatsComponent } from '../components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component';
 | 
					 | 
				
			||||||
import { FederationAddressesListComponent } from '../components/liquid-reserves-audit/federation-addresses-list/federation-addresses-list.component';
 | 
					import { FederationAddressesListComponent } from '../components/liquid-reserves-audit/federation-addresses-list/federation-addresses-list.component';
 | 
				
			||||||
import { ReservesRatioComponent } from '../components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component';
 | 
					 | 
				
			||||||
import { ReservesRatioStatsComponent } from '../components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component';
 | 
					 | 
				
			||||||
import { ReservesRatioGraphComponent } from '../components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routes: Routes = [
 | 
					const routes: Routes = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@ -77,18 +70,6 @@ const routes: Routes = [
 | 
				
			|||||||
        data: { preload: true, networkSpecific: true },
 | 
					        data: { preload: true, networkSpecific: true },
 | 
				
			||||||
        loadChildren: () => import('../components/block/block.module').then(m => m.BlockModule),
 | 
					        loadChildren: () => import('../components/block/block.module').then(m => m.BlockModule),
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        path: 'audit',
 | 
					 | 
				
			||||||
        data: { networks: ['liquid'] },
 | 
					 | 
				
			||||||
        component: StartComponent,
 | 
					 | 
				
			||||||
        children: [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            path: '',
 | 
					 | 
				
			||||||
            data: { networks: ['liquid'] },
 | 
					 | 
				
			||||||
            component: ReservesAuditDashboardComponent,
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        ]
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        path: 'audit/wallet',
 | 
					        path: 'audit/wallet',
 | 
				
			||||||
        data: { networks: ['liquid'] },
 | 
					        data: { networks: ['liquid'] },
 | 
				
			||||||
@ -180,17 +161,8 @@ export class LiquidRoutingModule { }
 | 
				
			|||||||
  ],
 | 
					  ],
 | 
				
			||||||
  declarations: [
 | 
					  declarations: [
 | 
				
			||||||
    LiquidMasterPageComponent,
 | 
					    LiquidMasterPageComponent,
 | 
				
			||||||
    ReservesAuditDashboardComponent,
 | 
					 | 
				
			||||||
    ReservesSupplyStatsComponent,
 | 
					 | 
				
			||||||
    RecentPegsStatsComponent,
 | 
					 | 
				
			||||||
    RecentPegsListComponent,
 | 
					 | 
				
			||||||
    FederationWalletComponent,
 | 
					    FederationWalletComponent,
 | 
				
			||||||
    FederationUtxosListComponent,
 | 
					    FederationUtxosListComponent,
 | 
				
			||||||
    FederationAddressesStatsComponent,
 | 
					 | 
				
			||||||
    FederationAddressesListComponent,
 | 
					 | 
				
			||||||
    ReservesRatioComponent,
 | 
					 | 
				
			||||||
    ReservesRatioStatsComponent,
 | 
					 | 
				
			||||||
    ReservesRatioGraphComponent,
 | 
					 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class LiquidMasterPageModule { }
 | 
					export class LiquidMasterPageModule { }
 | 
				
			||||||
@ -200,16 +200,20 @@ export class ApiService {
 | 
				
			|||||||
    return this.httpClient.get<FederationUtxo[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos');
 | 
					    return this.httpClient.get<FederationUtxo[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  recentPegOuts$(): Observable<RecentPeg[]> {
 | 
					  recentPegsList$(count: number = 0): Observable<RecentPeg[]> {
 | 
				
			||||||
    return this.httpClient.get<RecentPeg[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegouts');
 | 
					    return this.httpClient.get<RecentPeg[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/list/' + count);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  federationAddressesOneMonthAgo$(): Observable<any> {
 | 
					  pegsCount$(): Observable<any> {
 | 
				
			||||||
    return this.httpClient.get<FederationAddress[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/previous-month');
 | 
					    return this.httpClient.get<number>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/count');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  federationUtxosOneMonthAgo$(): Observable<any> {
 | 
					  federationAddressesNumber$(): Observable<any> {
 | 
				
			||||||
    return this.httpClient.get<FederationUtxo[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos/previous-month');
 | 
					    return this.httpClient.get<any>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/total');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  federationUtxosNumber$(): Observable<any> {
 | 
				
			||||||
 | 
					    return this.httpClient.get<any>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos/total');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  listFeaturedAssets$(): Observable<any[]> {
 | 
					  listFeaturedAssets$(): Observable<any[]> {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user