diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 6d6b2cd56..638e68003 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -72,6 +72,14 @@ class WebsocketHandler { } } + if (parsedMessage && parsedMessage['track-asset']) { + if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-asset'])) { + client['track-asset'] = parsedMessage['track-asset']; + } else { + client['track-asset'] = null; + } + } + if (parsedMessage.action === 'init') { const _blocks = blocks.getBlocks(); if (!_blocks) { @@ -155,24 +163,24 @@ class WebsocketHandler { } } - // Send all new incoming transactions related to tracked address - if (client['track-address']) { + // Send all new incoming transactions related to tracked asset + if (client['track-asset']) { const foundTransactions: TransactionExtended[] = []; newTransactions.forEach((tx) => { - const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']); + const someVin = tx.vin.some((vin) => !!vin.issuance && vin.issuance.asset_id === client['track-asset']); if (someVin) { foundTransactions.push(tx); return; } - const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']); + const someVout = tx.vout.some((vout) => !!vout.asset && vout.asset === client['track-asset']); if (someVout) { foundTransactions.push(tx); } }); if (foundTransactions.length) { - response['address-transactions'] = foundTransactions; + response['asset-transactions'] = foundTransactions; } } @@ -213,7 +221,34 @@ class WebsocketHandler { foundTransactions.push(tx); return; } - if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address'])) { + if (tx.vout && tx.vout.some((vout) => !!vout.asset && vout.asset === client['track-asset'])) { + foundTransactions.push(tx); + } + }); + + if (foundTransactions.length) { + foundTransactions.forEach((tx) => { + tx.status = { + confirmed: true, + block_height: block.height, + block_hash: block.id, + block_time: block.timestamp, + }; + }); + + response['asset-block-transactions'] = foundTransactions; + } + } + + if (client['track-asset']) { + const foundTransactions: TransactionExtended[] = []; + + transactions.forEach((tx) => { + if (tx.vin && tx.vin.some((vin) => !!vin.issuance && vin.issuance.asset_id === client['track-asset'])) { + foundTransactions.push(tx); + return; + } + if (tx.vout && tx.vout.some((vout) => !!vout.asset && vout.asset === client['track-asset'])) { foundTransactions.push(tx); } }); diff --git a/backend/src/interfaces.ts b/backend/src/interfaces.ts index b67c2b094..0360f727b 100644 --- a/backend/src/interfaces.ts +++ b/backend/src/interfaces.ts @@ -56,6 +56,20 @@ export interface Vin { sequence: any; witness?: string[]; inner_witnessscript_asm?: string; + + issuance?: Issuance; +} + +interface Issuance { + asset_id: string; + is_reissuance: string; + asset_blinding_nonce: string; + asset_entropy: string; + contract_hash: string; + assetamount?: number; + assetamountcommitment?: string; + tokenamount?: number; + tokenamountcommitment?: string; } export interface Vout { @@ -64,6 +78,8 @@ export interface Vout { scriptpubkey_type: string; scriptpubkey_address: string; value: number; + + asset?: string; } export interface Status { diff --git a/frontend/src/app/assets/assets.component.html b/frontend/src/app/assets/assets.component.html index 9163c9e0f..21c686dd9 100644 --- a/frontend/src/app/assets/assets.component.html +++ b/frontend/src/app/assets/assets.component.html @@ -7,7 +7,7 @@ - + diff --git a/frontend/src/app/assets/assets.component.ts b/frontend/src/app/assets/assets.component.ts index 8d3e6abda..89da94135 100644 --- a/frontend/src/app/assets/assets.component.ts +++ b/frontend/src/app/assets/assets.component.ts @@ -20,7 +20,11 @@ export class AssetsComponent implements OnInit { ) { } ngOnInit() { - this.assetsService.getAssetsJson$() + setTimeout(() => this.getAssets()); + } + + getAssets() { + this.assetsService.getAssetsJson$ .subscribe((assets) => { this.assets = Object.values(assets); this.assets.push({ @@ -36,6 +40,6 @@ export class AssetsComponent implements OnInit { this.error = error; this.isLoading = false; }); - } + } } diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index e4b2530e3..604637b21 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -15,7 +15,7 @@
NameName Ticker Issuer domain Asset ID
- + @@ -29,6 +29,20 @@ + + + + + + + + + + + + + +
Total received {{ receieved / 100000000 | number: '1.8-8' }} L-BTC{{ (receieved - sent) / 100000000 | number: '1.8-8' }} L-BTC ()
Total receivedConfidential
Total sentConfidential
BalanceConfidential
diff --git a/frontend/src/app/components/asset/asset.component.ts b/frontend/src/app/components/asset/asset.component.ts index 939a97715..e2c5a3624 100644 --- a/frontend/src/app/components/asset/asset.component.ts +++ b/frontend/src/app/components/asset/asset.component.ts @@ -84,7 +84,7 @@ export class AssetComponent implements OnInit, OnDestroy { console.log(err); return of(null); }) - ), this.assetsService.assetsMinimal$]) + ), this.assetsService.getAssetsMinimalJson$]) .pipe( take(1) ); @@ -141,7 +141,7 @@ export class AssetComponent implements OnInit, OnDestroy { this.isLoadingAsset = false; }); - this.stateService.mempoolTransactions$ + this.stateService.assetTransactions$ .subscribe((transaction) => { if (this.transactions.some((t) => t.txid === transaction.txid)) { return; @@ -151,22 +151,7 @@ export class AssetComponent implements OnInit, OnDestroy { this.transactions = this.transactions.slice(); this.txCount++; - // if (transaction.vout.some((vout) => vout.scriptpubkey_asset === this.asset.asset)) { - // this.audioService.playSound('cha-ching'); - // } else { - // this.audioService.playSound('chime'); - // } - - // transaction.vin.forEach((vin) => { - // if (vin.prevout.scriptpubkey_asset === this.asset.asset) { - // this.sent += vin.prevout.value; - // } - // }); - // transaction.vout.forEach((vout) => { - // if (vout.scriptpubkey_asset === this.asset.asset) { - // this.receieved += vout.value; - // } - // }); + this.audioService.playSound('chime'); }); this.stateService.blockTransactions$ diff --git a/frontend/src/app/components/clipboard/clipboard.component.html b/frontend/src/app/components/clipboard/clipboard.component.html index 0913c082e..7e7685607 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.html +++ b/frontend/src/app/components/clipboard/clipboard.component.html @@ -1,5 +1,5 @@ - \ No newline at end of file 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 6baf48d66..4500a6dd6 100644 --- a/frontend/src/app/components/search-form/search-form.component.ts +++ b/frontend/src/app/components/search-form/search-form.component.ts @@ -31,10 +31,12 @@ export class SearchFormComponent implements OnInit { this.searchForm = this.formBuilder.group({ searchText: ['', Validators.required], }); - this.assetsService.assetsMinimal$ - .subscribe((assets) => { - this.assets = assets; - }); + if (this.network === 'liquid') { + this.assetsService.getAssetsMinimalJson$ + .subscribe((assets) => { + this.assets = assets; + }); + } } search() { 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 7989f32c4..867963730 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -29,7 +29,7 @@
- Coinbase (Newly Generated Coins) + Coinbase (Newly Generated Coins) PEG IN 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 231c0ffb5..edd98eb68 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -35,9 +35,11 @@ export class TransactionsListComponent implements OnInit, OnChanges { ngOnInit() { this.latestBlock$ = this.stateService.blocks$; - this.assetsService.assetsMinimal$.subscribe((assets) => { - this.assetsMinimal = assets; - }); + if (this.network === 'liquid') { + this.assetsService.getAssetsMinimalJson$.subscribe((assets) => { + this.assetsMinimal = assets; + }); + } } ngOnChanges() { diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index cfdf5d59a..1cd2d4b8a 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -38,6 +38,19 @@ export interface Vin { witness?: string[]; inner_witnessscript_asm?: string; is_pegin?: boolean; + issuance?: Issuance; +} + +interface Issuance { + asset_id: string; + is_reissuance: string; + asset_blinding_nonce: string; + asset_entropy: string; + contract_hash: string; + assetamount?: number; + assetamountcommitment?: string; + tokenamount?: number; + tokenamountcommitment?: string; } export interface Vout { diff --git a/frontend/src/app/services/assets.service.ts b/frontend/src/app/services/assets.service.ts index 00cdc135d..dc8bf867e 100644 --- a/frontend/src/app/services/assets.service.ts +++ b/frontend/src/app/services/assets.service.ts @@ -1,7 +1,8 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { ReplaySubject } from 'rxjs'; +import { ReplaySubject, Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; +import { shareReplay } from 'rxjs/operators'; @Injectable({ providedIn: 'root' @@ -9,24 +10,13 @@ import { environment } from 'src/environments/environment'; export class AssetsService { network = environment.network; - assetsMinimal$ = new ReplaySubject(1); + getAssetsJson$: Observable; + getAssetsMinimalJson$: Observable; constructor( private httpClient: HttpClient, ) { - if (this.network === 'liquid') { - this.getAssetsMinimalJson$(); - } - } - - getAssetsMinimalJson$() { - this.httpClient.get('/resources/assets.minimal.json') - .subscribe((data) => { - this.assetsMinimal$.next(data); - }); - } - - getAssetsJson$() { - return this.httpClient.get('/resources/assets.json'); + this.getAssetsJson$ = this.httpClient.get('/resources/assets.json').pipe(shareReplay()); + this.getAssetsMinimalJson$ = this.httpClient.get('/resources/assets.minimal.json').pipe(shareReplay()); } } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 98a602ffd..e2b8c7687 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -21,6 +21,7 @@ export class StateService { mempoolBlocks$ = new ReplaySubject(1); txConfirmed$ = new Subject(); mempoolTransactions$ = new Subject(); + assetTransactions$ = new Subject(); blockTransactions$ = new Subject(); live2Chart$ = new Subject(); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 8ba46b3bb..2141535ea 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -96,6 +96,18 @@ export class WebsocketService { }); } + if (response['asset-transactions']) { + response['asset-transactions'].forEach((assetTransaction: Transaction) => { + this.stateService.assetTransactions$.next(assetTransaction); + }); + } + + if (response['asset-block-transactions']) { + response['asset-block-transactions'].forEach((addressTransaction: Transaction) => { + this.stateService.blockTransactions$.next(addressTransaction); + }); + } + if (response['live-2h-chart']) { this.stateService.live2Chart$.next(response['live-2h-chart']); }