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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get all of the federation addresses one month ago, most balances first
 | 
			
		||||
  public async $getFederationAddressesOneMonthAgo(): Promise<any> {
 | 
			
		||||
    const query = `
 | 
			
		||||
    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;`;
 | 
			
		||||
  // Get the total number of federation addresses
 | 
			
		||||
  public async $getFederationAddressesNumber(): Promise<any> {
 | 
			
		||||
    const query = `SELECT COUNT(DISTINCT bitcoinaddress) AS address_count FROM federation_txos WHERE unspent = 1;`;
 | 
			
		||||
    const [rows] = await DB.query(query);
 | 
			
		||||
    return rows[0];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Get all of the UTXOs held by the federation one month ago, most recent first
 | 
			
		||||
  public async $getFederationUtxosOneMonthAgo(): Promise<any> {
 | 
			
		||||
    const query = `
 | 
			
		||||
    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;`;
 | 
			
		||||
  // Get the total number of federation utxos
 | 
			
		||||
  public async $getFederationUtxosNumber(): Promise<any> {
 | 
			
		||||
    const query = `SELECT COUNT(*) AS utxo_count FROM federation_txos WHERE unspent = 1;`;
 | 
			
		||||
    const [rows] = await DB.query(query);
 | 
			
		||||
    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/pegouts', this.$getPegOuts)
 | 
			
		||||
        .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/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)
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
@ -142,12 +142,12 @@ class LiquidRoutes {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $getFederationAddressesOneMonthAgo(req: Request, res: Response) {
 | 
			
		||||
  private async $getFederationAddressesNumber(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const federationAddresses = await elementsParser.$getFederationAddressesOneMonthAgo();
 | 
			
		||||
      const federationAddresses = await elementsParser.$getFederationAddressesNumber();
 | 
			
		||||
      res.header('Pragma', '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);
 | 
			
		||||
    } catch (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 {
 | 
			
		||||
      const federationUtxos = await elementsParser.$getFederationUtxosOneMonthAgo();
 | 
			
		||||
      const federationUtxos = await elementsParser.$getFederationUtxosNumber();
 | 
			
		||||
      res.header('Pragma', '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);
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,15 @@
 | 
			
		||||
<div *ngIf="(federationAddresses$ | async) as federationAddresses; else loadingData">
 | 
			
		||||
  
 | 
			
		||||
    <div class="fee-estimation-container">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <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>
 | 
			
		||||
        </a>
 | 
			
		||||
        <div class="card-text">
 | 
			
		||||
          <div class="fee-text">{{ federationAddresses.length }} <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">
 | 
			
		||||
            <app-change [current]="federationAddresses.length" [previous]="federationAddressesOneMonthAgo.addresses_count_one_month"></app-change>
 | 
			
		||||
          </span>
 | 
			
		||||
        </div>
 | 
			
		||||
<div *ngIf="(federationWalletStats$ | async) as federationWalletStats; else loadingData">
 | 
			
		||||
  <div class="fee-estimation-container">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <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>
 | 
			
		||||
      </a>
 | 
			
		||||
      <div class="card-text">
 | 
			
		||||
        <div class="fee-text">{{ federationWalletStats.address_count }} <span i18n="shared.addresses">addresses</span></div>
 | 
			
		||||
        <div class="fiat">{{ federationWalletStats.utxo_count }} <span i18n="shared.utxos">UTXOs</span></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<ng-template #loadingData>
 | 
			
		||||
@ -30,5 +27,5 @@
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
<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>
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,7 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card-text {
 | 
			
		||||
      padding-top: 9px;
 | 
			
		||||
      font-size: 22px;
 | 
			
		||||
      span {
 | 
			
		||||
        font-size: 11px;
 | 
			
		||||
@ -49,10 +50,6 @@
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.loading-container{
 | 
			
		||||
  min-height: 76px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card-text {
 | 
			
		||||
  .skeleton-loader {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { FederationAddress } from '../../../interfaces/node-api.interface';
 | 
			
		||||
import { Observable, combineLatest, map } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-federation-addresses-stats',
 | 
			
		||||
@ -9,12 +8,21 @@ import { FederationAddress } from '../../../interfaces/node-api.interface';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class FederationAddressesStatsComponent implements OnInit {
 | 
			
		||||
  @Input() federationAddresses$: Observable<FederationAddress[]>;
 | 
			
		||||
  @Input() federationAddressesOneMonthAgo$: Observable<any>;
 | 
			
		||||
  @Input() federationAddressesNumber$: Observable<number>;
 | 
			
		||||
  @Input() federationUtxosNumber$: Observable<number>;
 | 
			
		||||
  federationWalletStats$: Observable<any>;
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  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="card smaller">
 | 
			
		||||
        <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>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,8 @@ export class ReservesAuditDashboardComponent implements OnInit {
 | 
			
		||||
  recentPegOuts$: Observable<RecentPeg[]>;
 | 
			
		||||
  pegsVolume$: Observable<PegsVolume[]>;
 | 
			
		||||
  federationAddresses$: Observable<FederationAddress[]>;
 | 
			
		||||
  federationAddressesOneMonthAgo$: Observable<any>;
 | 
			
		||||
  federationAddressesNumber$: Observable<number>;
 | 
			
		||||
  federationUtxosNumber$: Observable<number>;
 | 
			
		||||
  liquidPegsMonth$: Observable<any>;
 | 
			
		||||
  liquidReservesMonth$: Observable<any>;
 | 
			
		||||
  pegRatioGraphHeight: number = 320;
 | 
			
		||||
@ -143,11 +144,21 @@ export class ReservesAuditDashboardComponent implements OnInit {
 | 
			
		||||
      share()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    this.federationAddressesOneMonthAgo$ = interval(60 * 60 * 1000)
 | 
			
		||||
      .pipe(
 | 
			
		||||
        startWith(0),
 | 
			
		||||
        switchMap(() => this.apiService.federationAddressesOneMonthAgo$())
 | 
			
		||||
      );
 | 
			
		||||
    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(
 | 
			
		||||
 | 
			
		||||
@ -204,12 +204,12 @@ export class ApiService {
 | 
			
		||||
    return this.httpClient.get<RecentPeg[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/pegouts');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  federationAddressesOneMonthAgo$(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<FederationAddress[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/previous-month');
 | 
			
		||||
  federationAddressesNumber$(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/addresses/total');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  federationUtxosOneMonthAgo$(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<FederationUtxo[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos/previous-month');
 | 
			
		||||
  federationUtxosNumber$(): Observable<any> {
 | 
			
		||||
    return this.httpClient.get<any>(this.apiBaseUrl + this.apiBasePath + '/api/v1/liquid/reserves/utxos/total');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listFeaturedAssets$(): Observable<any[]> {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user