parent
d662292afb
commit
20c7ee98e7
@ -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') {
|
if (parsedMessage.action === 'init') {
|
||||||
const _blocks = blocks.getBlocks();
|
const _blocks = blocks.getBlocks();
|
||||||
if (!_blocks) {
|
if (!_blocks) {
|
||||||
@ -155,24 +163,24 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send all new incoming transactions related to tracked address
|
// Send all new incoming transactions related to tracked asset
|
||||||
if (client['track-address']) {
|
if (client['track-asset']) {
|
||||||
const foundTransactions: TransactionExtended[] = [];
|
const foundTransactions: TransactionExtended[] = [];
|
||||||
|
|
||||||
newTransactions.forEach((tx) => {
|
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) {
|
if (someVin) {
|
||||||
foundTransactions.push(tx);
|
foundTransactions.push(tx);
|
||||||
return;
|
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) {
|
if (someVout) {
|
||||||
foundTransactions.push(tx);
|
foundTransactions.push(tx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (foundTransactions.length) {
|
if (foundTransactions.length) {
|
||||||
response['address-transactions'] = foundTransactions;
|
response['asset-transactions'] = foundTransactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +221,34 @@ class WebsocketHandler {
|
|||||||
foundTransactions.push(tx);
|
foundTransactions.push(tx);
|
||||||
return;
|
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);
|
foundTransactions.push(tx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -56,6 +56,20 @@ export interface Vin {
|
|||||||
sequence: any;
|
sequence: any;
|
||||||
witness?: string[];
|
witness?: string[];
|
||||||
inner_witnessscript_asm?: 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 {
|
export interface Vout {
|
||||||
@ -64,6 +78,8 @@ export interface Vout {
|
|||||||
scriptpubkey_type: string;
|
scriptpubkey_type: string;
|
||||||
scriptpubkey_address: string;
|
scriptpubkey_address: string;
|
||||||
value: number;
|
value: number;
|
||||||
|
|
||||||
|
asset?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<ng-template [ngIf]="!isLoading && !error">
|
<ng-template [ngIf]="!isLoading && !error">
|
||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<th style="td-name">Name</th>
|
<th class="td-name">Name</th>
|
||||||
<th>Ticker</th>
|
<th>Ticker</th>
|
||||||
<th class="d-none d-md-block">Issuer domain</th>
|
<th class="d-none d-md-block">Issuer domain</th>
|
||||||
<th>Asset ID</th>
|
<th>Asset ID</th>
|
||||||
|
@ -20,7 +20,11 @@ export class AssetsComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.assetsService.getAssetsJson$()
|
setTimeout(() => this.getAssets());
|
||||||
|
}
|
||||||
|
|
||||||
|
getAssets() {
|
||||||
|
this.assetsService.getAssetsJson$
|
||||||
.subscribe((assets) => {
|
.subscribe((assets) => {
|
||||||
this.assets = Object.values(assets);
|
this.assets = Object.values(assets);
|
||||||
this.assets.push({
|
this.assets.push({
|
||||||
@ -36,6 +40,6 @@ export class AssetsComponent implements OnInit {
|
|||||||
this.error = error;
|
this.error = error;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody *ngIf="network !== 'liquid'">
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total received</td>
|
<td>Total received</td>
|
||||||
<td>{{ receieved / 100000000 | number: '1.8-8' }} <ng-template [ngIf]="network === 'liquid'">L-</ng-template>BTC</td>
|
<td>{{ receieved / 100000000 | number: '1.8-8' }} <ng-template [ngIf]="network === 'liquid'">L-</ng-template>BTC</td>
|
||||||
@ -29,6 +29,20 @@
|
|||||||
<td>{{ (receieved - sent) / 100000000 | number: '1.8-8' }} <ng-template [ngIf]="network === 'liquid'">L-</ng-template>BTC (<app-fiat [value]="receieved - sent"></app-fiat>)</td>
|
<td>{{ (receieved - sent) / 100000000 | number: '1.8-8' }} <ng-template [ngIf]="network === 'liquid'">L-</ng-template>BTC (<app-fiat [value]="receieved - sent"></app-fiat>)</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tbody *ngIf="network === 'liquid'">
|
||||||
|
<tr>
|
||||||
|
<td>Total received</td>
|
||||||
|
<td>Confidential</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total sent</td>
|
||||||
|
<td>Confidential</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Balance</td>
|
||||||
|
<td>Confidential</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col qrcode-col">
|
<div class="col qrcode-col">
|
||||||
|
@ -84,7 +84,7 @@ export class AssetComponent implements OnInit, OnDestroy {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
return of(null);
|
return of(null);
|
||||||
})
|
})
|
||||||
), this.assetsService.assetsMinimal$])
|
), this.assetsService.getAssetsMinimalJson$])
|
||||||
.pipe(
|
.pipe(
|
||||||
take(1)
|
take(1)
|
||||||
);
|
);
|
||||||
@ -141,7 +141,7 @@ export class AssetComponent implements OnInit, OnDestroy {
|
|||||||
this.isLoadingAsset = false;
|
this.isLoadingAsset = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.stateService.mempoolTransactions$
|
this.stateService.assetTransactions$
|
||||||
.subscribe((transaction) => {
|
.subscribe((transaction) => {
|
||||||
if (this.transactions.some((t) => t.txid === transaction.txid)) {
|
if (this.transactions.some((t) => t.txid === transaction.txid)) {
|
||||||
return;
|
return;
|
||||||
@ -151,22 +151,7 @@ export class AssetComponent implements OnInit, OnDestroy {
|
|||||||
this.transactions = this.transactions.slice();
|
this.transactions = this.transactions.slice();
|
||||||
this.txCount++;
|
this.txCount++;
|
||||||
|
|
||||||
// if (transaction.vout.some((vout) => vout.scriptpubkey_asset === this.asset.asset)) {
|
this.audioService.playSound('chime');
|
||||||
// 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.stateService.blockTransactions$
|
this.stateService.blockTransactions$
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<span #buttonWrapper [attr.data-tlite]="'Copied!'" style="position: relative;">
|
<span #buttonWrapper [attr.data-tlite]="'Copied!'" style="position: relative;">
|
||||||
<button #btn class="btn btn-sm btn-link pt-0" style="line-height: 1;" [attr.data-clipboard-text]="text">
|
<button #btn class="btn btn-sm btn-link pt-0" style="line-height: 0.9;" [attr.data-clipboard-text]="text">
|
||||||
<img src="./resources/clippy.svg" width="13">
|
<img src="./resources/clippy.svg" width="13">
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
@ -31,10 +31,12 @@ export class SearchFormComponent implements OnInit {
|
|||||||
this.searchForm = this.formBuilder.group({
|
this.searchForm = this.formBuilder.group({
|
||||||
searchText: ['', Validators.required],
|
searchText: ['', Validators.required],
|
||||||
});
|
});
|
||||||
this.assetsService.assetsMinimal$
|
if (this.network === 'liquid') {
|
||||||
.subscribe((assets) => {
|
this.assetsService.getAssetsMinimalJson$
|
||||||
this.assets = assets;
|
.subscribe((assets) => {
|
||||||
});
|
this.assets = assets;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
search() {
|
search() {
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div [ngSwitch]="true">
|
<div [ngSwitch]="true">
|
||||||
<ng-container *ngSwitchCase="vin.is_coinbase">Coinbase (Newly Generated Coins)</ng-container>
|
<ng-container *ngSwitchCase="vin.is_coinbase">Coinbase<ng-template [ngIf]="network !== 'liquid'"> (Newly Generated Coins)</ng-template></ng-container>
|
||||||
<ng-container *ngSwitchCase="vin.is_pegin">PEG IN</ng-container>
|
<ng-container *ngSwitchCase="vin.is_pegin">PEG IN</ng-container>
|
||||||
<ng-container *ngSwitchDefault>
|
<ng-container *ngSwitchDefault>
|
||||||
<a [routerLink]="['/address/', vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
|
<a [routerLink]="['/address/', vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
|
||||||
|
@ -35,9 +35,11 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.latestBlock$ = this.stateService.blocks$;
|
this.latestBlock$ = this.stateService.blocks$;
|
||||||
this.assetsService.assetsMinimal$.subscribe((assets) => {
|
if (this.network === 'liquid') {
|
||||||
this.assetsMinimal = assets;
|
this.assetsService.getAssetsMinimalJson$.subscribe((assets) => {
|
||||||
});
|
this.assetsMinimal = assets;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
|
@ -38,6 +38,19 @@ export interface Vin {
|
|||||||
witness?: string[];
|
witness?: string[];
|
||||||
inner_witnessscript_asm?: string;
|
inner_witnessscript_asm?: string;
|
||||||
is_pegin?: boolean;
|
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 {
|
export interface Vout {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { ReplaySubject } from 'rxjs';
|
import { ReplaySubject, Observable } from 'rxjs';
|
||||||
import { environment } from 'src/environments/environment';
|
import { environment } from 'src/environments/environment';
|
||||||
|
import { shareReplay } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@ -9,24 +10,13 @@ import { environment } from 'src/environments/environment';
|
|||||||
export class AssetsService {
|
export class AssetsService {
|
||||||
network = environment.network;
|
network = environment.network;
|
||||||
|
|
||||||
assetsMinimal$ = new ReplaySubject<any>(1);
|
getAssetsJson$: Observable<any>;
|
||||||
|
getAssetsMinimalJson$: Observable<any>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private httpClient: HttpClient,
|
private httpClient: HttpClient,
|
||||||
) {
|
) {
|
||||||
if (this.network === 'liquid') {
|
this.getAssetsJson$ = this.httpClient.get('/resources/assets.json').pipe(shareReplay());
|
||||||
this.getAssetsMinimalJson$();
|
this.getAssetsMinimalJson$ = this.httpClient.get('/resources/assets.minimal.json').pipe(shareReplay());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getAssetsMinimalJson$() {
|
|
||||||
this.httpClient.get('/resources/assets.minimal.json')
|
|
||||||
.subscribe((data) => {
|
|
||||||
this.assetsMinimal$.next(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getAssetsJson$() {
|
|
||||||
return this.httpClient.get('/resources/assets.json');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ export class StateService {
|
|||||||
mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);
|
mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);
|
||||||
txConfirmed$ = new Subject<Block>();
|
txConfirmed$ = new Subject<Block>();
|
||||||
mempoolTransactions$ = new Subject<Transaction>();
|
mempoolTransactions$ = new Subject<Transaction>();
|
||||||
|
assetTransactions$ = new Subject<Transaction>();
|
||||||
blockTransactions$ = new Subject<Transaction>();
|
blockTransactions$ = new Subject<Transaction>();
|
||||||
|
|
||||||
live2Chart$ = new Subject<OptimizedMempoolStats>();
|
live2Chart$ = new Subject<OptimizedMempoolStats>();
|
||||||
|
@ -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']) {
|
if (response['live-2h-chart']) {
|
||||||
this.stateService.live2Chart$.next(response['live-2h-chart']);
|
this.stateService.live2Chart$.next(response['live-2h-chart']);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user