From 11b1d9bbd39655b8c621dbfee9d2887cb88892e8 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sat, 2 May 2020 12:36:35 +0700 Subject: [PATCH] Assets support WIP refs #37 --- .../components/amount/amount.component.html | 2 +- .../app/components/asset/asset.component.html | 14 ++++---- .../app/components/asset/asset.component.ts | 33 ++++++++++++------- .../search-form/search-form.component.ts | 16 ++++++++- .../television/television.component.scss | 4 +-- .../transactions-list.component.html | 21 ++++++++++-- .../transactions-list.component.ts | 13 ++++++++ .../src/app/interfaces/electrs.interface.ts | 15 +-------- .../scriptpubkey-type.pipe.ts | 2 +- frontend/src/app/services/assets.service.ts | 29 ++++++++++++++++ frontend/src/environments/environment.prod.ts | 1 + frontend/src/environments/environment.ts | 1 + 12 files changed, 110 insertions(+), 41 deletions(-) create mode 100644 frontend/src/app/services/assets.service.ts diff --git a/frontend/src/app/components/amount/amount.component.html b/frontend/src/app/components/amount/amount.component.html index e18508e1e..b8d632b02 100644 --- a/frontend/src/app/components/amount/amount.component.html +++ b/frontend/src/app/components/amount/amount.component.html @@ -2,7 +2,7 @@ {{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }} - + Confidential diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index d91ff40bd..4c24ca1b1 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -9,7 +9,7 @@
- +
@@ -18,15 +18,15 @@ Name - {{ asset.name }} ({{ asset.ticker }}) + {{ assetContract[2] }} ({{ assetContract[1] }}) Precision - {{ asset.precision }} + {{ assetContract[3] }} Issuer - {{ asset.contract.entity.domain }} + {{ assetContract[0] }} Issuance tx @@ -40,15 +40,15 @@ Circulating amount - {{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + asset.precision }} + {{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + assetContract[3] }} Issued amount - {{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + asset.precision }} + {{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + assetContract[3] }} Burned amount - {{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + asset.precision }} + {{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + assetContract[3] }} diff --git a/frontend/src/app/components/asset/asset.component.ts b/frontend/src/app/components/asset/asset.component.ts index e444382a8..1e471f7f5 100644 --- a/frontend/src/app/components/asset/asset.component.ts +++ b/frontend/src/app/components/asset/asset.component.ts @@ -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; diff --git a/frontend/src/app/components/search-form/search-form.component.ts b/frontend/src/app/components/search-form/search-form.component.ts index da07ddad7..6baf48d66 100644 --- a/frontend/src/app/components/search-form/search-form.component.ts +++ b/frontend/src/app/components/search-form/search-form.component.ts @@ -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; diff --git a/frontend/src/app/components/television/television.component.scss b/frontend/src/app/components/television/television.component.scss index 60011f43d..5055c64d3 100644 --- a/frontend/src/app/components/television/television.component.scss +++ b/frontend/src/app/components/television/television.component.scss @@ -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); 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 d03d065c9..4ba949633 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -70,10 +70,22 @@ - + +
+ {{ vout.value / 100000000 | number: '1.0-' + assetsMinimal[vout.asset][3] }} {{ assetsMinimal[vout.asset][1] }} +
+ {{ assetsMinimal[vout.asset][0] }} +
+ {{ vout.asset | shortenString : 13 }} +

+
+
+ + + - + @@ -97,7 +109,10 @@   diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index f2bf48af5..231c0ffb5 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -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; 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); } diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index 47c3a3af1..f0673e04a 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -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; } diff --git a/frontend/src/app/pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe.ts b/frontend/src/app/pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe.ts index 7c9239517..d4725a2c5 100644 --- a/frontend/src/app/pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe.ts +++ b/frontend/src/app/pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe.ts @@ -11,7 +11,7 @@ export class ScriptpubkeyTypePipe implements PipeTransform { return 'Transaction fee'; case 'op_return': default: - return 'Script'; + return 'OP_RETURN'; } } diff --git a/frontend/src/app/services/assets.service.ts b/frontend/src/app/services/assets.service.ts new file mode 100644 index 000000000..41f3fa69a --- /dev/null +++ b/frontend/src/app/services/assets.service.ts @@ -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(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); + }); + } +} diff --git a/frontend/src/environments/environment.prod.ts b/frontend/src/environments/environment.prod.ts index 397bcb4c1..9683e3f3e 100644 --- a/frontend/src/environments/environment.prod.ts +++ b/frontend/src/environments/environment.prod.ts @@ -5,4 +5,5 @@ const sub = parts[0]; export const environment = { production: true, network: sub, + nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d', }; diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index a537d5cc7..f8ca8345f 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -5,6 +5,7 @@ export const environment = { production: false, network: 'mainnet', + nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d', }; /*