parent
							
								
									3839edbaaa
								
							
						
					
					
						commit
						53653f96c8
					
				@ -2,7 +2,7 @@
 | 
			
		||||
  <span>{{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
 | 
			
		||||
</ng-container>
 | 
			
		||||
<ng-template #viewFiatVin>
 | 
			
		||||
  <ng-template [ngIf]="network === 'liquid' && !satoshis" [ngIfElse]="default">
 | 
			
		||||
  <ng-template [ngIf]="network === 'liquid' && satoshis === undefined" [ngIfElse]="default">
 | 
			
		||||
    Confidential
 | 
			
		||||
  </ng-template>
 | 
			
		||||
  <ng-template #default>
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="!isLoadingAsset && !error">
 | 
			
		||||
  <ng-template [ngIf]="!isLoadingAsset && !error && assetContract">
 | 
			
		||||
    <div class="box">
 | 
			
		||||
 | 
			
		||||
      <div class="row">
 | 
			
		||||
@ -18,15 +18,15 @@
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Name</td>
 | 
			
		||||
                <td>{{ asset.name }} ({{ asset.ticker }})</td>
 | 
			
		||||
                <td>{{ assetContract[2] }} ({{ assetContract[1] }})</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Precision</td>
 | 
			
		||||
                <td>{{ asset.precision }}</td>
 | 
			
		||||
                <td>{{ assetContract[3] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Issuer</td>
 | 
			
		||||
                <td><a target="_blank" href="{{ 'http://' + asset.contract.entity.domain }}">{{ asset.contract.entity.domain }}</a></td>
 | 
			
		||||
                <td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Issuance tx</td>
 | 
			
		||||
@ -40,15 +40,15 @@
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Circulating amount</td>
 | 
			
		||||
                <td>{{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + asset.precision }}</td>
 | 
			
		||||
                <td>{{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + assetContract[3] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Issued amount</td>
 | 
			
		||||
                <td>{{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + asset.precision }}</td>
 | 
			
		||||
                <td>{{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + assetContract[3] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Burned amount</td>
 | 
			
		||||
                <td>{{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + asset.precision }}</td>
 | 
			
		||||
                <td>{{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + assetContract[3] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
          </table>
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,16 @@
 | 
			
		||||
import { Component, OnInit, OnDestroy } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute, ParamMap } from '@angular/router';
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { switchMap, filter, catchError } from 'rxjs/operators';
 | 
			
		||||
import { switchMap, filter, catchError, take } from 'rxjs/operators';
 | 
			
		||||
import { Asset, Transaction } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { WebsocketService } from 'src/app/services/websocket.service';
 | 
			
		||||
import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { AudioService } from 'src/app/services/audio.service';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { of, merge, Subscription } from 'rxjs';
 | 
			
		||||
import { of, merge, Subscription, combineLatest } from 'rxjs';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
import { AssetsService } from 'src/app/services/assets.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-asset',
 | 
			
		||||
@ -20,6 +21,7 @@ export class AssetComponent implements OnInit, OnDestroy {
 | 
			
		||||
  network = environment.network;
 | 
			
		||||
 | 
			
		||||
  asset: Asset;
 | 
			
		||||
  assetContract: any;
 | 
			
		||||
  assetString: string;
 | 
			
		||||
  isLoadingAsset = true;
 | 
			
		||||
  transactions: Transaction[];
 | 
			
		||||
@ -45,6 +47,7 @@ export class AssetComponent implements OnInit, OnDestroy {
 | 
			
		||||
    private audioService: AudioService,
 | 
			
		||||
    private apiService: ApiService,
 | 
			
		||||
    private seoService: SeoService,
 | 
			
		||||
    private assetsService: AssetsService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
@ -57,6 +60,7 @@ export class AssetComponent implements OnInit, OnDestroy {
 | 
			
		||||
          this.isLoadingAsset = true;
 | 
			
		||||
          this.loadedConfirmedTxCount = 0;
 | 
			
		||||
          this.asset = null;
 | 
			
		||||
          this.assetContract = null;
 | 
			
		||||
          this.isLoadingTransactions = true;
 | 
			
		||||
          this.transactions = null;
 | 
			
		||||
          document.body.scrollTo(0, 0);
 | 
			
		||||
@ -69,22 +73,27 @@ export class AssetComponent implements OnInit, OnDestroy {
 | 
			
		||||
              .pipe(filter((state) => state === 2 && this.transactions && this.transactions.length > 0))
 | 
			
		||||
          )
 | 
			
		||||
          .pipe(
 | 
			
		||||
            switchMap(() => this.electrsApiService.getAsset$(this.assetString)
 | 
			
		||||
            switchMap(() => {
 | 
			
		||||
              return combineLatest([this.electrsApiService.getAsset$(this.assetString)
 | 
			
		||||
                .pipe(
 | 
			
		||||
                  catchError((err) => {
 | 
			
		||||
                    this.isLoadingAsset = false;
 | 
			
		||||
                    this.error = err;
 | 
			
		||||
                    console.log(err);
 | 
			
		||||
                    return of(null);
 | 
			
		||||
                  })
 | 
			
		||||
                ), this.assetsService.assetsMinimal$])
 | 
			
		||||
              .pipe(
 | 
			
		||||
                catchError((err) => {
 | 
			
		||||
                  this.isLoadingAsset = false;
 | 
			
		||||
                  this.error = err;
 | 
			
		||||
                  console.log(err);
 | 
			
		||||
                  return of(null);
 | 
			
		||||
                })
 | 
			
		||||
              )
 | 
			
		||||
            )
 | 
			
		||||
                take(1)
 | 
			
		||||
              );
 | 
			
		||||
            })
 | 
			
		||||
          );
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
      .pipe(
 | 
			
		||||
        switchMap((asset: Asset) => {
 | 
			
		||||
        switchMap(([asset, assetsData]) => {
 | 
			
		||||
          this.asset = asset;
 | 
			
		||||
          this.assetContract = assetsData[this.asset.asset_id];
 | 
			
		||||
          this.updateChainStats();
 | 
			
		||||
          this.websocketService.startTrackAsset(asset.asset_id);
 | 
			
		||||
          this.isLoadingAsset = false;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
import { Component, OnInit, ChangeDetectionStrategy, EventEmitter, Output } from '@angular/core';
 | 
			
		||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
import { AssetsService } from 'src/app/services/assets.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-search-form',
 | 
			
		||||
@ -9,6 +11,9 @@ import { Router } from '@angular/router';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
			
		||||
})
 | 
			
		||||
export class SearchFormComponent implements OnInit {
 | 
			
		||||
  network = environment.network;
 | 
			
		||||
  assets: object;
 | 
			
		||||
 | 
			
		||||
  searchForm: FormGroup;
 | 
			
		||||
  @Output() searchTriggered = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
@ -19,12 +24,17 @@ export class SearchFormComponent implements OnInit {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private formBuilder: FormBuilder,
 | 
			
		||||
    private router: Router,
 | 
			
		||||
    private assetsService: AssetsService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.searchForm = this.formBuilder.group({
 | 
			
		||||
      searchText: ['', Validators.required],
 | 
			
		||||
    });
 | 
			
		||||
    this.assetsService.assetsMinimal$
 | 
			
		||||
      .subscribe((assets) => {
 | 
			
		||||
        this.assets = assets;
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  search() {
 | 
			
		||||
@ -37,7 +47,11 @@ export class SearchFormComponent implements OnInit {
 | 
			
		||||
        this.router.navigate(['/block/', searchText]);
 | 
			
		||||
        this.searchTriggered.emit();
 | 
			
		||||
      } else if (this.regexTransaction.test(searchText)) {
 | 
			
		||||
        this.router.navigate(['/tx/', searchText]);
 | 
			
		||||
        if (this.network === 'liquid' && this.assets[searchText]) {
 | 
			
		||||
          this.router.navigate(['/asset/', searchText]);
 | 
			
		||||
        } else {
 | 
			
		||||
          this.router.navigate(['/tx/', searchText]);
 | 
			
		||||
        }
 | 
			
		||||
        this.searchTriggered.emit();
 | 
			
		||||
      } else {
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@
 | 
			
		||||
.position-container {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  bottom: 150px;
 | 
			
		||||
  bottom: 170px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.chart-holder {
 | 
			
		||||
@ -37,7 +37,7 @@
 | 
			
		||||
@media (min-width: 1920px) {
 | 
			
		||||
  .position-container {
 | 
			
		||||
    transform: scale(1.3);
 | 
			
		||||
    bottom: 190px;
 | 
			
		||||
    bottom: 210px;
 | 
			
		||||
  }
 | 
			
		||||
  .chart-holder {
 | 
			
		||||
    height: calc(100% - 280px);
 | 
			
		||||
 | 
			
		||||
@ -70,10 +70,22 @@
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td class="text-right nowrap">
 | 
			
		||||
                <app-amount [satoshis]="vout.value"></app-amount>
 | 
			
		||||
                <ng-template [ngIf]="vout.asset && vout.scriptpubkey_type === 'op_return' && vout.asset !== nativeAssetId" [ngIfElse]="defaultOutput">
 | 
			
		||||
                  <div *ngIf="assetsMinimal && assetsMinimal[vout.asset]">
 | 
			
		||||
                    {{ vout.value / 100000000 | number: '1.0-' + assetsMinimal[vout.asset][3] }} {{ assetsMinimal[vout.asset][1] }}
 | 
			
		||||
                    <br>
 | 
			
		||||
                    {{ assetsMinimal[vout.asset][0] }}
 | 
			
		||||
                    <br>
 | 
			
		||||
                    <a [routerLink]="['/asset/', vout.asset]">{{ vout.asset | shortenString : 13 }}</a>
 | 
			
		||||
                    <br><br>
 | 
			
		||||
                </div>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <ng-template #defaultOutput>
 | 
			
		||||
                  <app-amount [satoshis]="vout.value"></app-amount>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td class="pl-1 arrow-td">
 | 
			
		||||
                <i *ngIf="!outspends[i]; else outspend" class="arrow grey"></i>
 | 
			
		||||
                <i *ngIf="!outspends[i] || vout.scriptpubkey_type === 'op_return' || vout.scriptpubkey_type === 'fee' ; else outspend" class="arrow grey"></i>
 | 
			
		||||
                <ng-template #outspend>
 | 
			
		||||
                  <i *ngIf="!outspends[i][vindex] || !outspends[i][vindex].spent; else spent" class="arrow green"></i>
 | 
			
		||||
                  <ng-template #spent>
 | 
			
		||||
@ -97,7 +109,10 @@
 | 
			
		||||
                   
 | 
			
		||||
                </span>
 | 
			
		||||
                <button type="button" class="btn btn-sm btn-primary mt-3" (click)="switchCurrency()">
 | 
			
		||||
                  <app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
 | 
			
		||||
                  <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="defaultAmount">Confidential</ng-template>
 | 
			
		||||
                  <ng-template #defaultAmount>
 | 
			
		||||
                    <app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </button>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,8 @@ import { StateService } from '../../services/state.service';
 | 
			
		||||
import { Observable, forkJoin } from 'rxjs';
 | 
			
		||||
import { Block, Outspend, Transaction } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
import { AssetsService } from 'src/app/services/assets.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-transactions-list',
 | 
			
		||||
@ -11,6 +13,9 @@ import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
			
		||||
})
 | 
			
		||||
export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
  network = environment.network;
 | 
			
		||||
  nativeAssetId = environment.nativeAssetId;
 | 
			
		||||
 | 
			
		||||
  @Input() transactions: Transaction[];
 | 
			
		||||
  @Input() showConfirmations = false;
 | 
			
		||||
  @Input() transactionPage = false;
 | 
			
		||||
@ -19,15 +24,20 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
 | 
			
		||||
  latestBlock$: Observable<Block>;
 | 
			
		||||
  outspends: Outspend[] = [];
 | 
			
		||||
  assetsMinimal: any;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
    private electrsApiService: ElectrsApiService,
 | 
			
		||||
    private assetsService: AssetsService,
 | 
			
		||||
    private ref: ChangeDetectorRef,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.latestBlock$ = this.stateService.blocks$;
 | 
			
		||||
    this.assetsService.assetsMinimal$.subscribe((assets) => {
 | 
			
		||||
      this.assetsMinimal = assets;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnChanges() {
 | 
			
		||||
@ -66,6 +76,9 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switchCurrency() {
 | 
			
		||||
    if (this.network === 'liquid') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const oldvalue = !this.stateService.viewFiat$.value;
 | 
			
		||||
    this.stateService.viewFiat$.next(oldvalue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -45,6 +45,7 @@ export interface Vout {
 | 
			
		||||
  scriptpubkey_type: string;
 | 
			
		||||
  scriptpubkey_address: string;
 | 
			
		||||
  value: number;
 | 
			
		||||
  asset?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Status {
 | 
			
		||||
@ -108,11 +109,6 @@ export interface Asset {
 | 
			
		||||
  status: Status;
 | 
			
		||||
  chain_stats: AssetChainStats;
 | 
			
		||||
  mempool_stats: AssetMempoolStats;
 | 
			
		||||
  contract: Contract;
 | 
			
		||||
  entity: Entity;
 | 
			
		||||
  precision: number;
 | 
			
		||||
  name: string;
 | 
			
		||||
  ticker: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IssuanceTxin {
 | 
			
		||||
@ -157,15 +153,6 @@ interface AssetMempoolStats {
 | 
			
		||||
  burn_count: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Contract {
 | 
			
		||||
  entity: Entity;
 | 
			
		||||
  issuer_pubkey: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
  precision: number;
 | 
			
		||||
  ticker: string;
 | 
			
		||||
  version: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Entity {
 | 
			
		||||
  domain: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ export class ScriptpubkeyTypePipe implements PipeTransform {
 | 
			
		||||
        return 'Transaction fee';
 | 
			
		||||
      case 'op_return':
 | 
			
		||||
      default:
 | 
			
		||||
          return 'Script';
 | 
			
		||||
          return 'OP_RETURN';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								frontend/src/app/services/assets.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								frontend/src/app/services/assets.service.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import { ReplaySubject } from 'rxjs';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
})
 | 
			
		||||
export class AssetsService {
 | 
			
		||||
  network = environment.network;
 | 
			
		||||
 | 
			
		||||
  assetsMinimal$ = new ReplaySubject<any>(1);
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private httpClient: HttpClient,
 | 
			
		||||
  ) {
 | 
			
		||||
    if (this.network === 'liquid') {
 | 
			
		||||
      this.getAssetsMinimalJson$();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAssetsMinimalJson$() {
 | 
			
		||||
    this.httpClient.get('/assets/assets.minimal.json')
 | 
			
		||||
    .subscribe((data) => {
 | 
			
		||||
      console.log(data);
 | 
			
		||||
      this.assetsMinimal$.next(data);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -5,4 +5,5 @@ const sub = parts[0];
 | 
			
		||||
export const environment = {
 | 
			
		||||
  production: true,
 | 
			
		||||
  network: sub,
 | 
			
		||||
  nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
export const environment = {
 | 
			
		||||
  production: false,
 | 
			
		||||
  network: 'mainnet',
 | 
			
		||||
  nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user