Change federation wallet stats to include utxos count
This commit is contained in:
parent
42bd08c744
commit
346c024ddf
@ -398,31 +398,16 @@ 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];
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,9 @@ class LiquidRoutes {
|
|||||||
.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/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 +142,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,12 +166,12 @@ 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);
|
||||||
|
@ -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>
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card-text {
|
.card-text {
|
||||||
|
padding-top: 9px;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
span {
|
span {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
@ -49,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 } from 'rxjs';
|
||||||
import { FederationAddress } from '../../../interfaces/node-api.interface';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-federation-addresses-stats',
|
selector: 'app-federation-addresses-stats',
|
||||||
@ -9,12 +8,21 @@ 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$,
|
||||||
|
this.federationUtxosNumber$
|
||||||
|
]).pipe(
|
||||||
|
map(([address_count, utxo_count]) => {
|
||||||
|
return { address_count, utxo_count}
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<div class="col" style="margin-bottom: 1.47rem">
|
<div class="col" style="margin-bottom: 1.47rem">
|
||||||
<div class="card smaller">
|
<div class="card smaller">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<app-federation-addresses-stats [federationAddresses$]="federationAddresses$" [federationAddressesOneMonthAgo$]="federationAddressesOneMonthAgo$"></app-federation-addresses-stats>
|
<app-federation-addresses-stats [federationAddressesNumber$]="federationAddressesNumber$" [federationUtxosNumber$]="federationUtxosNumber$"></app-federation-addresses-stats>
|
||||||
<app-federation-addresses-list [federationAddresses$]="federationAddresses$" [widget]="true"></app-federation-addresses-list>
|
<app-federation-addresses-list [federationAddresses$]="federationAddresses$" [widget]="true"></app-federation-addresses-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,8 @@ export class ReservesAuditDashboardComponent implements OnInit {
|
|||||||
recentPegOuts$: Observable<RecentPeg[]>;
|
recentPegOuts$: Observable<RecentPeg[]>;
|
||||||
pegsVolume$: Observable<PegsVolume[]>;
|
pegsVolume$: Observable<PegsVolume[]>;
|
||||||
federationAddresses$: Observable<FederationAddress[]>;
|
federationAddresses$: Observable<FederationAddress[]>;
|
||||||
federationAddressesOneMonthAgo$: Observable<any>;
|
federationAddressesNumber$: Observable<number>;
|
||||||
|
federationUtxosNumber$: Observable<number>;
|
||||||
liquidPegsMonth$: Observable<any>;
|
liquidPegsMonth$: Observable<any>;
|
||||||
liquidReservesMonth$: Observable<any>;
|
liquidReservesMonth$: Observable<any>;
|
||||||
pegRatioGraphHeight: number = 320;
|
pegRatioGraphHeight: number = 320;
|
||||||
@ -143,10 +144,20 @@ export class ReservesAuditDashboardComponent implements OnInit {
|
|||||||
share()
|
share()
|
||||||
);
|
);
|
||||||
|
|
||||||
this.federationAddressesOneMonthAgo$ = interval(60 * 60 * 1000)
|
this.federationAddressesNumber$ = this.auditUpdated$.pipe(
|
||||||
.pipe(
|
filter(auditUpdated => auditUpdated === true),
|
||||||
startWith(0),
|
throttleTime(40000),
|
||||||
switchMap(() => this.apiService.federationAddressesOneMonthAgo$())
|
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)
|
this.liquidPegsMonth$ = interval(60 * 60 * 1000)
|
||||||
|
@ -204,12 +204,12 @@ export class ApiService {
|
|||||||
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/pegouts');
|
||||||
}
|
}
|
||||||
|
|
||||||
federationAddressesOneMonthAgo$(): Observable<any> {
|
federationAddressesNumber$(): Observable<any> {
|
||||||
return this.httpClient.get<FederationAddress[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/previous-month');
|
return this.httpClient.get<any>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/total');
|
||||||
}
|
}
|
||||||
|
|
||||||
federationUtxosOneMonthAgo$(): Observable<any> {
|
federationUtxosNumber$(): 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/utxos/total');
|
||||||
}
|
}
|
||||||
|
|
||||||
listFeaturedAssets$(): Observable<any[]> {
|
listFeaturedAssets$(): Observable<any[]> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user