mirror of
https://github.com/mempool/mempool.git
synced 2025-01-18 21:32:55 +01:00
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…
Reference in New Issue
Block a user