diff --git a/backend/src/api/liquid/elements-parser.ts b/backend/src/api/liquid/elements-parser.ts index 05f35c085..8c3d519ab 100644 --- a/backend/src/api/liquid/elements-parser.ts +++ b/backend/src/api/liquid/elements-parser.ts @@ -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 { + 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(); diff --git a/backend/src/api/liquid/liquid.routes.ts b/backend/src/api/liquid/liquid.routes.ts index 64d631a05..b87348d1b 100644 --- a/backend/src/api/liquid/liquid.routes.ts +++ b/backend/src/api/liquid/liquid.routes.ts @@ -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(); diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.html b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.html index d562328a5..b0683389e 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.html +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.html @@ -18,7 +18,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -57,7 +57,7 @@ ‎{{ peg.blocktime * 1000 | date:'yyyy-MM-dd HH:mm' }}
()
- + diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.scss b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.scss index 92f5bc64f..4bb89d781 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.scss +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.scss @@ -105,3 +105,16 @@ tr, td, th { .debit { color: #D81B60; } + +.glow-effect { + animation: color-oscillation 1s ease-in-out infinite alternate; +} + +@keyframes color-oscillation { + 0% { + color: #777983; + } + 100% { + color: #D81B60; + } +} diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.ts b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.ts index e921e1250..d839d891f 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component.ts @@ -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`); diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.html b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.html index fca78b881..2a853ff5d 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.html +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.html @@ -1,7 +1,47 @@ -
-
- -
Recent Peg-In / Out's 
-
+
+ +
+
+
+
+{{ (+pegsVolume[0].volume) / 100000000 | number: '1.2-2' }} BTC
+
{{ (+pegsVolume[0].number) }} Peg-Ins
+
+
+
+
+
{{ (+pegsVolume[1].volume) / 100000000 | number: '1.2-2' }} BTC
+
{{ (+pegsVolume[1].number) }} Peg-Outs
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.scss b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.scss index 0534c9b5d..658094609 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.scss +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.scss @@ -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; +} \ No newline at end of file diff --git a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.ts b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.ts index 3fbebf715..7bf8e6910 100644 --- a/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/recent-pegs-stats/recent-pegs-stats.component.ts @@ -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; + constructor() { } ngOnInit(): void { - } } diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.html b/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.html index e9f6b4ccd..47d6e7aed 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.html +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.html @@ -25,7 +25,7 @@
- +
diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.ts b/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.ts index 9b23eb7cb..2133f0fe2 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.ts @@ -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; recentPegIns$: Observable; recentPegOuts$: Observable; + pegsVolume$: Observable; federationAddresses$: Observable; federationAddressesOneMonthAgo$: Observable; liquidPegsMonth$: Observable; @@ -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), diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 24d34d6ec..625a7c70e 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -33,7 +33,7 @@ - + @@ -204,7 +204,7 @@ Peg-out to - + diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index cebb23f27..eaeeca94c 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -82,6 +82,11 @@ export interface CurrentPegs { hash: string; } +export interface PegsVolume { + volume: string; + number: number; +} + export interface FederationAddress { bitcoinaddress: string; balance: string; diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 38060d47d..bd20ec36e 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -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(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs'); } + pegsVolume$(): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/volume'); + } + listLiquidPegsMonth$(): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegs/month'); }