diff --git a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts index 9931fb78a..c37c59544 100644 --- a/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts +++ b/frontend/src/app/components/lbtc-pegs-graph/lbtc-pegs-graph.component.ts @@ -18,7 +18,7 @@ import { EChartsOption } from '../../graphs/echarts'; }) export class LbtcPegsGraphComponent implements OnInit, OnChanges { @Input() data: any; - @Input() height: number | string = '320'; + @Input() height: number | string = '270'; pegsChartOptions: EChartsOption; right: number | string = '10'; diff --git a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html index 1db3c1924..dd07645bf 100644 --- a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html +++ b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html @@ -78,9 +78,6 @@ - diff --git a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.scss b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.scss index a6766232c..d6aaccff1 100644 --- a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.scss +++ b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.scss @@ -23,21 +23,11 @@ li.nav-item { margin: auto 10px; padding-left: 10px; padding-right: 10px; - @media (max-width: 992px) { - margin: auto 7px; - padding-left: 8px; - padding-right: 8px; - } @media (max-width: 429px) { margin: auto 5px; padding-left: 6px; padding-right: 6px; } - @media (max-width: 369px) { - margin: auto 3px; - padding-left: 4px; - padding-right: 4px; - } } @media (min-width: 992px) { diff --git a/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts b/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts index 64ee97079..61650fdb4 100644 --- a/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts @@ -20,6 +20,9 @@ export class FederationAddressesStatsComponent implements OnInit { this.federationUtxosNumber$ ?? of(undefined) ]).pipe( map(([address_count, utxo_count]) => { + if (address_count === undefined || utxo_count === undefined) { + return undefined; + } return { address_count, utxo_count} }) ) 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 9df119cfc..d8c60113f 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 @@ -15,7 +15,7 @@ import { SeoService } from '../../../services/seo.service'; }) export class RecentPegsListComponent implements OnInit { @Input() widget: boolean = false; - @Input() recentPegsList$: Observable = of([]); + @Input() recentPegsList$: Observable; env: Env; isLoading = true; 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 deleted file mode 100644 index 47457324b..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.html +++ /dev/null @@ -1,98 +0,0 @@ -
- -
- -
-
-
- - -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- - -
-
-
- -
-
-
- - -
-
-
-
-
- - - -
- -
- -
-
-
- - -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
-
- - -
-
-
- -
-
-
- - -
-
-
-
-
-
- - - -
- Audit in progress: Bitcoin block height #{{ auditStatus.lastBlockAudit }} / #{{ auditStatus.bitcoinHeaders }} -
-
-
\ No newline at end of file diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.scss b/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.scss deleted file mode 100644 index 7b2aea1fa..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.scss +++ /dev/null @@ -1,135 +0,0 @@ -.dashboard-container { - text-align: center; - margin-top: 0.5rem; - .col { - margin-bottom: 1.5rem; - } -} - -.card { - background-color: #1d1f31; - height: 418px; - @media (min-width: 992px) { - height: 512px; - } - &.smaller { - height: 408px; - } -} - -.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%; - } -} - -.mempool-block-wrapper { - max-height: 380px; - max-width: 380px; - margin: auto; -} \ No newline at end of file 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 deleted file mode 100644 index 78cb607d4..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-audit-dashboard/reserves-audit-dashboard.component.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { ChangeDetectionStrategy, Component, HostListener, 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; - auditUpdated$: Observable; - currentPeg$: Observable; - currentReserves$: Observable; - recentPegsList$: Observable; - pegsVolume$: Observable; - federationAddresses$: Observable; - federationAddressesNumber$: Observable; - federationUtxosNumber$: Observable; - liquidPegsMonth$: Observable; - liquidReservesMonth$: Observable; - pegRatioGraphHeight: number = 320; - fullHistory$: Observable; - 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.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( - 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(); - } - - @HostListener('window:resize', ['$event']) - onResize(): void { - if (window.innerWidth >= 992) { - this.pegRatioGraphHeight = 320; - } else if (window.innerWidth >= 768) { - this.pegRatioGraphHeight = 230; - } else { - this.pegRatioGraphHeight = 220; - } - } - -} diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.html b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.html deleted file mode 100644 index cffb73c06..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
-
\ No newline at end of file diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.scss b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.scss deleted file mode 100644 index 9881148fc..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.scss +++ /dev/null @@ -1,6 +0,0 @@ -.loadingGraphs { - position: absolute; - top: 50%; - left: calc(50% - 16px); - z-index: 100; -} \ No newline at end of file diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.ts b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.ts deleted file mode 100644 index 9b48466e3..000000000 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio-graph.component.ts +++ /dev/null @@ -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; - @Input() height: number | string = '320'; - ratioHistoryChartOptions: EChartsOption; - ratioSeries: number[] = []; - - 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) => ``; - let itemFormatted = '
' + params[0].axisValue + '
'; - 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 += `
-
${colorSpan(item.color)}
-
-
${symbol}${formattedValue}
-
`; - return `
${itemFormatted}
`; - } - }, - 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' - } - }, - }; - } -} - diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts index efe3df2e1..bd0a015f3 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts @@ -95,7 +95,7 @@ export class ReservesRatioComponent implements OnInit, OnChanges { }, title: { show: true, - offsetCenter: [0, '-117.5%'], + offsetCenter: [0, '-127%'], fontSize: 18, color: '#4a68b9', fontFamily: 'inherit', diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component.html b/frontend/src/app/components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component.html index 5a76f3820..65b40f39c 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component.html +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-supply-stats/reserves-supply-stats.component.html @@ -1,44 +1,29 @@ -
-
-
-
-
L-BTC in circulation
-
-
{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} L-BTC
- - As of block {{ currentPeg.lastBlockUpdate }} - -
-
-
-
BTC Holdings
-
-
{{ (+currentReserves.amount) / 100000000 | number: '1.2-2' }} BTC
- - As of block {{ currentReserves.lastBlockUpdate }} - -
-
+
+
+
L-BTC in circulation
+
+
{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} L-BTC
+ + As of block {{ currentPeg.lastBlockUpdate }} + +
+
+
+
BTC Holdings
+
+
{{ (+currentReserves.amount) / 100000000 | number: '1.2-2' }} BTC
+ + As of block {{ currentReserves.lastBlockUpdate }} +
+ -
-
-
L-BTC in circulation
-
-
-
-
-
-
-
BTC Holdings
-
-
-
-
-
+
+
+
diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 29feba485..bb79cc94d 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -1,7 +1,7 @@ -
+
- +
Transaction Fees
@@ -17,35 +17,26 @@
- - -
Mempool Goggles: {{ goggleCycle[goggleIndex].name }}
-   - -
-
-
- -
+ +
Mempool Goggles: {{ goggleCycle[goggleIndex].name }}
+   + +
+
+
+
-
- -
- - -
- -
-
- -
+
+
+ +
@@ -53,7 +44,6 @@
-
Incoming Transactions
-
-
-
- - - - - - - - -
- - - - - {{ group.name }} -
-
-
+
Recent Replacements
@@ -171,7 +142,7 @@
- Confidential + Confidential @@ -184,26 +155,52 @@
- - - - - - - - - - -
-
-
-
-
-
-
-
-
-
+ +
+ +
+ +
+
+
+ + +
+
+
+ +
+
+
+ +
+
Peg Historical Data
+
+ +
+
+
+ +
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+
+
+
@@ -283,21 +280,56 @@
- -
-
-
L-BTC in circulation
- -
{{ (+currentPeg.amount) / 100000000 | number: '1.2-2' }} L-BTC
-
-
-
- -
BTC Reserves 
-
- -
{{ +(currentReserves.amount) / 100000000 | number: '1.2-2' }} BTC
-
+ +
+ +
+ +
+
+
+ + +
+
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ + + +
+ Audit in progress: Bitcoin block height #{{ auditStatus.lastBlockAudit }} / #{{ auditStatus.bitcoinHeaders }} +
+
+
\ No newline at end of file diff --git a/frontend/src/app/dashboard/dashboard.component.scss b/frontend/src/app/dashboard/dashboard.component.scss index fd20b629e..019a79994 100644 --- a/frontend/src/app/dashboard/dashboard.component.scss +++ b/frontend/src/app/dashboard/dashboard.component.scss @@ -413,3 +413,39 @@ margin-top: 5px; 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; +} + +.peg-historical-data { + font-size: 18px; + + @media (min-width: 768px) { + padding-top: 22px; + } + + @media (min-width: 992px) { + padding-top: 27px; + } +} + +.in-progress-message { + position: relative; + color: #ffffff91; + margin-top: 20px; + text-align: center; + padding-bottom: 3px; + font-weight: 500; +} diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 5dfd68419..89d6de96e 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -1,7 +1,7 @@ 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 { 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 { ApiService } from '../services/api.service'; import { StateService } from '../services/state.service'; @@ -32,8 +32,6 @@ interface MempoolStatsData { changeDetection: ChangeDetectionStrategy.OnPush }) export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { - featuredAssets$: Observable; - nbFeaturedAssets = 6; network$: Observable; mempoolBlocksData$: Observable; mempoolInfoData$: Observable; @@ -53,13 +51,18 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { auditUpdated$: Observable; liquidReservesMonth$: Observable; currentReserves$: Observable; + recentPegsList$: Observable; + pegsVolume$: Observable; + federationAddresses$: Observable; + federationAddressesNumber$: Observable; + federationUtxosNumber$: Observable; fullHistory$: Observable; isLoad: boolean = true; mempoolInfoSubscription: Subscription; currencySubscription: Subscription; currency: string; incomingGraphHeight: number = 300; - lbtcPegGraphHeight: number = 320; + lbtcPegGraphHeight: number = 250; private lastPegBlockUpdate: number = 0; private lastPegAmount: string = ''; private lastReservesBlockUpdate: number = 0; @@ -155,26 +158,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$ .pipe( scan((acc, tx) => { @@ -240,7 +223,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { share(), ); - if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { + if (this.stateService.network === 'liquid') { this.auditStatus$ = this.stateService.blocks$.pipe( takeUntil(this.destroy$), throttleTime(40000), @@ -250,22 +233,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { 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( switchMap(_ => this.apiService.liquidPegs$().pipe( @@ -278,7 +245,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { share() ); - ////////// BTC Reserves historical data ////////// this.auditUpdated$ = combineLatest([ this.auditStatus$, this.currentPeg$ @@ -293,21 +259,6 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { const amountCheck = currentPegAmount !== this.lastPegAmount; this.lastPegAmount = currentPegAmount; 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() ); @@ -326,11 +277,78 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { 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( 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) { @@ -342,7 +360,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { labels: [] }; } - + return { liquidPegs, liquidReserves @@ -374,24 +392,21 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { getArrayFromNumber(num: number): number[] { return Array.from({ length: num }, (_, i) => i + 1); } - + @HostListener('window:resize', ['$event']) onResize(): void { if (window.innerWidth >= 992) { this.incomingGraphHeight = 300; this.goggleResolution = 82; - this.lbtcPegGraphHeight = 320; - this.nbFeaturedAssets = 6; + this.lbtcPegGraphHeight = 270; } else if (window.innerWidth >= 768) { this.incomingGraphHeight = 215; this.goggleResolution = 80; - this.lbtcPegGraphHeight = 230; - this.nbFeaturedAssets = 4; + this.lbtcPegGraphHeight = 190; } else { this.incomingGraphHeight = 180; this.goggleResolution = 86; - this.lbtcPegGraphHeight = 220; - this.nbFeaturedAssets = 4; + this.lbtcPegGraphHeight = 200; } } } diff --git a/frontend/src/app/graphs/graphs.module.ts b/frontend/src/app/graphs/graphs.module.ts index 85905d1f1..42aebe613 100644 --- a/frontend/src/app/graphs/graphs.module.ts +++ b/frontend/src/app/graphs/graphs.module.ts @@ -12,6 +12,13 @@ import { FeeDistributionGraphComponent } from '../components/fee-distribution-gr import { IncomingTransactionsGraphComponent } from '../components/incoming-transactions-graph/incoming-transactions-graph.component'; import { MempoolGraphComponent } from '../components/mempool-graph/mempool-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 { StatisticsComponent } from '../components/statistics/statistics.component'; import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component'; @@ -48,6 +55,13 @@ import { CommonModule } from '@angular/common'; IncomingTransactionsGraphComponent, MempoolGraphComponent, LbtcPegsGraphComponent, + ReservesSupplyStatsComponent, + ReservesRatioStatsComponent, + ReservesRatioComponent, + RecentPegsStatsComponent, + RecentPegsListComponent, + FederationAddressesStatsComponent, + FederationAddressesListComponent, HashrateChartComponent, HashrateChartPoolsComponent, BlockHealthGraphComponent, diff --git a/frontend/src/app/liquid/liquid-master-page.module.ts b/frontend/src/app/liquid/liquid-master-page.module.ts index 0134365bc..8988cb05c 100644 --- a/frontend/src/app/liquid/liquid-master-page.module.ts +++ b/frontend/src/app/liquid/liquid-master-page.module.ts @@ -15,17 +15,10 @@ import { AssetsComponent } from '../components/assets/assets.component'; import { AssetsFeaturedComponent } from '../components/assets/assets-featured/assets-featured.component' import { AssetComponent } from '../components/asset/asset.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 { 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 { 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 { 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 = [ { @@ -77,18 +70,6 @@ const routes: Routes = [ data: { preload: true, networkSpecific: true }, 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', data: { networks: ['liquid'] }, @@ -180,17 +161,8 @@ export class LiquidRoutingModule { } ], declarations: [ LiquidMasterPageComponent, - ReservesAuditDashboardComponent, - ReservesSupplyStatsComponent, - RecentPegsStatsComponent, - RecentPegsListComponent, FederationWalletComponent, FederationUtxosListComponent, - FederationAddressesStatsComponent, - FederationAddressesListComponent, - ReservesRatioComponent, - ReservesRatioStatsComponent, - ReservesRatioGraphComponent, ] }) export class LiquidMasterPageModule { } \ No newline at end of file