2020-04-28 17:10:31 +07:00
import { Component , OnInit , OnDestroy } from '@angular/core' ;
import { ActivatedRoute , ParamMap } from '@angular/router' ;
import { ElectrsApiService } from '../../services/electrs-api.service' ;
2020-05-02 12:36:35 +07:00
import { switchMap , filter , catchError , take } from 'rxjs/operators' ;
2020-04-28 17:10:31 +07:00
import { Asset , Transaction } from '../../interfaces/electrs.interface' ;
2022-09-21 17:23:45 +02:00
import { WebsocketService } from '../../services/websocket.service' ;
import { StateService } from '../../services/state.service' ;
import { AudioService } from '../../services/audio.service' ;
import { ApiService } from '../../services/api.service' ;
2020-05-02 12:36:35 +07:00
import { of , merge , Subscription , combineLatest } from 'rxjs' ;
2022-09-21 17:23:45 +02:00
import { SeoService } from '../../services/seo.service' ;
2022-11-24 12:19:19 +09:00
import { environment } from '../../../environments/environment' ;
2022-09-21 17:23:45 +02:00
import { AssetsService } from '../../services/assets.service' ;
import { moveDec } from '../../bitcoin.utils' ;
2020-04-28 17:10:31 +07:00
@Component ( {
selector : 'app-asset' ,
templateUrl : './asset.component.html' ,
styleUrls : [ './asset.component.scss' ]
} )
export class AssetComponent implements OnInit , OnDestroy {
2020-05-09 20:37:50 +07:00
network = '' ;
2021-12-28 17:59:11 +04:00
nativeAssetId = this . stateService . network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId ;
2020-04-28 17:10:31 +07:00
asset : Asset ;
2020-11-22 16:19:57 +07:00
blindedIssuance : boolean ;
2020-05-02 12:36:35 +07:00
assetContract : any ;
2020-04-28 17:10:31 +07:00
assetString : string ;
isLoadingAsset = true ;
transactions : Transaction [ ] ;
isLoadingTransactions = true ;
2020-05-02 16:29:34 +07:00
isNativeAsset = false ;
2020-04-28 17:10:31 +07:00
error : any ;
mainSubscription : Subscription ;
2022-01-20 19:47:18 +04:00
imageError = false ;
2020-04-28 17:10:31 +07:00
totalConfirmedTxCount = 0 ;
loadedConfirmedTxCount = 0 ;
txCount = 0 ;
receieved = 0 ;
sent = 0 ;
private tempTransactions : Transaction [ ] ;
private timeTxIndexes : number [ ] ;
private lastTransactionTxId : string ;
constructor (
private route : ActivatedRoute ,
private electrsApiService : ElectrsApiService ,
private websocketService : WebsocketService ,
private stateService : StateService ,
private audioService : AudioService ,
private apiService : ApiService ,
private seoService : SeoService ,
2020-05-02 12:36:35 +07:00
private assetsService : AssetsService ,
2020-04-28 17:10:31 +07:00
) { }
ngOnInit() {
2020-09-21 19:41:12 +07:00
this . websocketService . want ( [ 'blocks' , 'mempool-blocks' ] ) ;
2020-05-09 20:37:50 +07:00
this . stateService . networkChanged $ . subscribe ( ( network ) = > this . network = network ) ;
2020-04-28 17:10:31 +07:00
this . mainSubscription = this . route . paramMap
. pipe (
switchMap ( ( params : ParamMap ) = > {
this . error = undefined ;
2022-02-06 04:18:56 +04:00
this . imageError = false ;
2020-04-28 17:10:31 +07:00
this . isLoadingAsset = true ;
this . loadedConfirmedTxCount = 0 ;
this . asset = null ;
2020-05-02 12:36:35 +07:00
this . assetContract = null ;
2020-04-28 17:10:31 +07:00
this . isLoadingTransactions = true ;
this . transactions = null ;
document . body . scrollTo ( 0 , 0 ) ;
this . assetString = params . get ( 'id' ) || '' ;
2020-12-04 21:29:31 +07:00
this . seoService . setTitle ( $localize ` :@@asset.component.asset-browser-title:Asset: ${ this . assetString } :INTERPOLATION: ` ) ;
2020-04-28 17:10:31 +07:00
return merge (
of ( true ) ,
this . stateService . connectionState $
. pipe ( filter ( ( state ) = > state === 2 && this . transactions && this . transactions . length > 0 ) )
)
. pipe (
2020-05-02 12:36:35 +07:00
switchMap ( ( ) = > {
return combineLatest ( [ this . electrsApiService . getAsset $ ( this . assetString )
. pipe (
catchError ( ( err ) = > {
this . isLoadingAsset = false ;
this . error = err ;
2023-03-09 02:34:21 -06:00
this . seoService . logSoft404 ( ) ;
2020-05-02 12:36:35 +07:00
console . log ( err ) ;
return of ( null ) ;
} )
2020-05-05 15:26:23 +07:00
) , this . assetsService . getAssetsMinimalJson $ ] )
2020-04-28 17:10:31 +07:00
. pipe (
2020-05-02 12:36:35 +07:00
take ( 1 )
) ;
} )
2020-04-28 17:10:31 +07:00
) ;
} )
)
. pipe (
2020-05-02 12:36:35 +07:00
switchMap ( ( [ asset , assetsData ] ) = > {
2020-04-28 17:10:31 +07:00
this . asset = asset ;
2020-05-02 12:36:35 +07:00
this . assetContract = assetsData [ this . asset . asset_id ] ;
2020-11-22 16:03:23 +07:00
if ( ! this . assetContract ) {
this . assetContract = [ null , '?' , 'Unknown' , 0 ] ;
}
2023-09-06 22:42:33 +09:00
this . seoService . setDescription ( $localize ` :@@meta.description.liquid.asset:Browse an overview of the Liquid asset ${ this . assetContract [ 2 ] } :INTERPOLATION: ( ${ this . assetContract [ 1 ] } :INTERPOLATION:): see issued amount, burned amount, circulating amount, related transactions, and more. ` ) ;
2020-11-22 16:19:57 +07:00
this . blindedIssuance = this . asset . chain_stats . has_blinded_issuances || this . asset . mempool_stats . has_blinded_issuances ;
2020-05-02 16:29:34 +07:00
this . isNativeAsset = asset . asset_id === this . nativeAssetId ;
2020-04-28 17:10:31 +07:00
this . updateChainStats ( ) ;
this . websocketService . startTrackAsset ( asset . asset_id ) ;
this . isLoadingAsset = false ;
this . isLoadingTransactions = true ;
return this . electrsApiService . getAssetTransactions $ ( asset . asset_id ) ;
} ) ,
switchMap ( ( transactions ) = > {
this . tempTransactions = transactions ;
if ( transactions . length ) {
this . lastTransactionTxId = transactions [ transactions . length - 1 ] . txid ;
this . loadedConfirmedTxCount += transactions . filter ( ( tx ) = > tx . status . confirmed ) . length ;
}
const fetchTxs : string [ ] = [ ] ;
this . timeTxIndexes = [ ] ;
transactions . forEach ( ( tx , index ) = > {
if ( ! tx . status . confirmed ) {
fetchTxs . push ( tx . txid ) ;
this . timeTxIndexes . push ( index ) ;
}
} ) ;
if ( ! fetchTxs . length ) {
return of ( [ ] ) ;
}
return this . apiService . getTransactionTimes $ ( fetchTxs ) ;
} )
)
. subscribe ( ( times : number [ ] ) = > {
times . forEach ( ( time , index ) = > {
this . tempTransactions [ this . timeTxIndexes [ index ] ] . firstSeen = time ;
} ) ;
this . tempTransactions . sort ( ( a , b ) = > {
2021-09-25 16:28:11 +04:00
if ( b . status . confirmed ) {
if ( b . status . block_height === a . status . block_height ) {
return b . status . block_time - a . status . block_time ;
}
return b . status . block_height - a . status . block_height ;
}
return b . firstSeen - a . firstSeen ;
2020-04-28 17:10:31 +07:00
} ) ;
this . transactions = this . tempTransactions ;
this . isLoadingTransactions = false ;
} ,
( error ) = > {
console . log ( error ) ;
this . error = error ;
2023-03-09 02:34:21 -06:00
this . seoService . logSoft404 ( ) ;
2020-04-28 17:10:31 +07:00
this . isLoadingAsset = false ;
} ) ;
2020-05-20 17:00:50 +07:00
this . stateService . mempoolTransactions $
2020-04-28 17:10:31 +07:00
. subscribe ( ( transaction ) = > {
if ( this . transactions . some ( ( t ) = > t . txid === transaction . txid ) ) {
return ;
}
this . transactions . unshift ( transaction ) ;
this . transactions = this . transactions . slice ( ) ;
this . txCount ++ ;
2020-05-05 15:26:23 +07:00
this . audioService . playSound ( 'chime' ) ;
2020-04-28 17:10:31 +07:00
} ) ;
this . stateService . blockTransactions $
. subscribe ( ( transaction ) = > {
const tx = this . transactions . find ( ( t ) = > t . txid === transaction . txid ) ;
if ( tx ) {
tx . status = transaction . status ;
this . transactions = this . transactions . slice ( ) ;
this . audioService . playSound ( 'magic' ) ;
}
this . totalConfirmedTxCount ++ ;
this . loadedConfirmedTxCount ++ ;
} ) ;
}
loadMore() {
if ( this . isLoadingTransactions || ! this . totalConfirmedTxCount || this . loadedConfirmedTxCount >= this . totalConfirmedTxCount ) {
return ;
}
this . isLoadingTransactions = true ;
2020-05-03 00:56:48 +07:00
this . electrsApiService . getAssetTransactionsFromHash $ ( this . asset . asset_id , this . lastTransactionTxId )
2020-04-28 17:10:31 +07:00
. subscribe ( ( transactions : Transaction [ ] ) = > {
this . lastTransactionTxId = transactions [ transactions . length - 1 ] . txid ;
this . loadedConfirmedTxCount += transactions . length ;
this . transactions = this . transactions . concat ( transactions ) ;
this . isLoadingTransactions = false ;
} ) ;
}
updateChainStats() {
// this.receieved = this.asset.chain_stats.funded_txo_sum + this.asset.mempool_stats.funded_txo_sum;
// this.sent = this.asset.chain_stats.spent_txo_sum + this.asset.mempool_stats.spent_txo_sum;
this . txCount = this . asset . chain_stats . tx_count + this . asset . mempool_stats . tx_count ;
2020-05-03 00:56:48 +07:00
this . totalConfirmedTxCount = this . asset . chain_stats . tx_count ;
2020-04-28 17:10:31 +07:00
}
2020-09-29 03:54:56 +07:00
formatAmount ( value : number , precision = 0 ) : number | string {
return moveDec ( value , - precision ) ;
}
2020-04-28 17:10:31 +07:00
ngOnDestroy() {
this . mainSubscription . unsubscribe ( ) ;
this . websocketService . stopTrackingAsset ( ) ;
}
}