Add peg ins/out volume to stats components
This commit is contained in:
		
							parent
							
								
									602c87bea0
								
							
						
					
					
						commit
						b561648082
					
				@ -433,6 +433,16 @@ class ElementsParser {
 | 
			
		||||
    const [rows] = await DB.query(query);
 | 
			
		||||
    return rows;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get all peg in / out from the last month
 | 
			
		||||
  public async $getPegsVolumeDaily(): Promise<any> {
 | 
			
		||||
    const pegInQuery = await DB.query(`SELECT SUM(amount) AS volume, COUNT(*) AS number FROM elements_pegs WHERE amount > 0 and datetime > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -1, CURRENT_TIMESTAMP()));`);
 | 
			
		||||
    const pegOutQuery = await DB.query(`SELECT SUM(amount) AS volume, COUNT(*) AS number FROM elements_pegs WHERE amount < 0 and datetime > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -1, CURRENT_TIMESTAMP()));`);
 | 
			
		||||
    return [
 | 
			
		||||
      pegInQuery[0][0],
 | 
			
		||||
      pegOutQuery[0][0]
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new ElementsParser();
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ class LiquidRoutes {
 | 
			
		||||
      app
 | 
			
		||||
        .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/volume', this.$getPegsVolumeDaily)
 | 
			
		||||
        .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/pegouts', this.$getPegOuts)
 | 
			
		||||
@ -189,6 +190,18 @@ class LiquidRoutes {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $getPegsVolumeDaily(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const pegsVolume = await elementsParser.$getPegsVolumeDaily();
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
      res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
 | 
			
		||||
      res.json(pegsVolume);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new LiquidRoutes();
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody *ngIf="recentPegs$ | async as pegs; else skeleton" [style]="isLoading ? 'opacity: 0.75' : ''">
 | 
			
		||||
          <ng-container *ngIf="widget; else regularRows">
 | 
			
		||||
            <tr *ngFor="let peg of pegs | slice:0:6">
 | 
			
		||||
            <tr *ngFor="let peg of pegs | slice:0:5">
 | 
			
		||||
              <td class="transaction text-left widget">
 | 
			
		||||
                <ng-container *ngIf="peg.amount > 0">
 | 
			
		||||
                  <a [routerLink]="['/tx' | relativeUrl, peg.txid]" [fragment]="'vin=' + peg.txindex">
 | 
			
		||||
 | 
			
		||||
@ -47,7 +47,7 @@ export class RecentPegsListComponent implements OnInit {
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.isLoading = !this.widget;
 | 
			
		||||
    this.env = this.stateService.env;
 | 
			
		||||
    this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
 | 
			
		||||
    this.skeletonLines = this.widget === true ? [...Array(5).keys()] : [...Array(15).keys()];
 | 
			
		||||
 | 
			
		||||
    if (!this.widget) {
 | 
			
		||||
      this.seoService.setTitle($localize`:@@a8b0889ea1b41888f1e247f2731cc9322198ca04:Recent Peg-In / Out's`);
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,47 @@
 | 
			
		||||
<div class="fee-estimation-container">
 | 
			
		||||
  <div class="item">
 | 
			
		||||
    <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]">
 | 
			
		||||
      <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
			
		||||
    </a>
 | 
			
		||||
<div *ngIf="(pegsVolume$ | async) as pegsVolume; else loadingData">
 | 
			
		||||
  <div class="fee-estimation-container">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]">
 | 
			
		||||
        <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
			
		||||
      </a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="fee-estimation-container">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <div class="card-text">
 | 
			
		||||
        <div class="fee-text credit" i18n-ngbTooltip="liquid.peg-ins-volume-day" ngbTooltip="24h Peg-In Volume" placement="top">+{{ (+pegsVolume[0].volume) / 100000000 | number: '1.2-2' }} <span i18n="shared.addresses">BTC</span></div>
 | 
			
		||||
        <div class="fiat">{{ (+pegsVolume[0].number) }} <span i18n="liquid.peg-ins">Peg-Ins</span></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <div class="card-text">
 | 
			
		||||
        <div class="fee-text debit" i18n-ngbTooltip="liquid.peg-out-volume-day" ngbTooltip="24h Peg-Out Volume" placement="top">{{ (+pegsVolume[1].volume) / 100000000 | number: '1.2-2' }} <span i18n="shared.addresses">BTC</span></div>
 | 
			
		||||
        <div class="fiat">{{ (+pegsVolume[1].number) }} <span i18n="liquid.peg-outs">Peg-Outs</span></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<ng-template #loadingData>
 | 
			
		||||
  <div class="fee-estimation-container loading-container">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <a class="title-link" [routerLink]="['/audit/pegs' | relativeUrl]">
 | 
			
		||||
        <h5 class="card-title"><ng-container i18n="liquid.recent-pegs">Recent Peg-In / Out's</ng-container> <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="font-size: 13px; color: #4a68b9"></fa-icon></h5>
 | 
			
		||||
      </a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="fee-estimation-container">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <div class="card-text">
 | 
			
		||||
        <div class="skeleton-loader"></div>
 | 
			
		||||
        <div class="skeleton-loader"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <div class="card-text">
 | 
			
		||||
        <div class="skeleton-loader"></div>
 | 
			
		||||
        <div class="skeleton-loader"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
.fee-estimation-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding-bottom: 1rem;
 | 
			
		||||
  @media (min-width: 376px) {
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
  }  
 | 
			
		||||
@ -36,6 +35,7 @@
 | 
			
		||||
      top: 0px;
 | 
			
		||||
    }
 | 
			
		||||
    .fee-text{
 | 
			
		||||
      border-bottom: 1px solid #ffffff1c;
 | 
			
		||||
      width: fit-content;
 | 
			
		||||
      margin: auto;
 | 
			
		||||
      line-height: 1.45;
 | 
			
		||||
@ -69,3 +69,11 @@
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  color: inherit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.credit {
 | 
			
		||||
  color: #7CB342;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.debit {
 | 
			
		||||
  color: #D81B60;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,7 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { PegsVolume } from '../../../interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-recent-pegs-stats',
 | 
			
		||||
  templateUrl: './recent-pegs-stats.component.html',
 | 
			
		||||
@ -6,10 +9,11 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class RecentPegsStatsComponent implements OnInit {
 | 
			
		||||
  @Input() pegsVolume$: Observable<PegsVolume[]>;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <app-recent-pegs-stats></app-recent-pegs-stats>
 | 
			
		||||
          <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>
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@ 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, RecentPeg } from '../../../interfaces/node-api.interface';
 | 
			
		||||
import { AuditStatus, CurrentPegs, FederationAddress, FederationUtxo, PegsVolume, RecentPeg } from '../../../interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-reserves-audit-dashboard',
 | 
			
		||||
@ -20,6 +20,7 @@ export class ReservesAuditDashboardComponent implements OnInit {
 | 
			
		||||
  federationUtxos$: Observable<FederationUtxo[]>;
 | 
			
		||||
  recentPegIns$: Observable<RecentPeg[]>;
 | 
			
		||||
  recentPegOuts$: Observable<RecentPeg[]>;
 | 
			
		||||
  pegsVolume$: Observable<PegsVolume[]>;
 | 
			
		||||
  federationAddresses$: Observable<FederationAddress[]>;
 | 
			
		||||
  federationAddressesOneMonthAgo$: Observable<any>;
 | 
			
		||||
  liquidPegsMonth$: Observable<any>;
 | 
			
		||||
@ -127,6 +128,13 @@ export class ReservesAuditDashboardComponent implements OnInit {
 | 
			
		||||
      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),
 | 
			
		||||
 | 
			
		||||
@ -82,6 +82,11 @@ export interface CurrentPegs {
 | 
			
		||||
  hash: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PegsVolume {
 | 
			
		||||
  volume: string;
 | 
			
		||||
  number: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FederationAddress { 
 | 
			
		||||
  bitcoinaddress: string;
 | 
			
		||||
  balance: string;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
 | 
			
		||||
import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators,
 | 
			
		||||
  PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit, Acceleration, AccelerationHistoryParams, CurrentPegs, AuditStatus, FederationAddress, FederationUtxo, RecentPeg } from '../interfaces/node-api.interface';
 | 
			
		||||
  PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit, Acceleration, AccelerationHistoryParams, CurrentPegs, AuditStatus, FederationAddress, FederationUtxo, RecentPeg, PegsVolume } from '../interfaces/node-api.interface';
 | 
			
		||||
import { BehaviorSubject, Observable, catchError, filter, of, shareReplay, take, tap } from 'rxjs';
 | 
			
		||||
import { StateService } from './state.service';
 | 
			
		||||
import { IBackendInfo, WebsocketResponse } from '../interfaces/websocket.interface';
 | 
			
		||||
@ -182,6 +182,10 @@ export class ApiService {
 | 
			
		||||
    return this.httpClient.get<CurrentPegs>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pegsVolume$(): Observable<PegsVolume[]> {
 | 
			
		||||
    return this.httpClient.get<PegsVolume[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/volume');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listLiquidPegsMonth$(): Observable<LiquidPegs[]> {
 | 
			
		||||
    return this.httpClient.get<LiquidPegs[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/month');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user