mirror of
https://github.com/mempool/mempool.git
synced 2025-02-23 14:40:38 +01:00
parent
ac9e718ef1
commit
44d19550e8
13 changed files with 217 additions and 41 deletions
|
@ -11,6 +11,7 @@ import { StatisticsComponent } from './components/statistics/statistics.componen
|
|||
import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component';
|
||||
import { LatestBlocksComponent } from './components/latest-blocks/latest-blocks.component';
|
||||
import { AssetComponent } from './components/asset/asset.component';
|
||||
import { AssetsComponent } from './assets/assets.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
|
@ -37,10 +38,6 @@ const routes: Routes = [
|
|||
path: 'mempool-block/:id',
|
||||
component: MempoolBlockComponent
|
||||
},
|
||||
{
|
||||
path: 'asset/:id',
|
||||
component: AssetComponent
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -56,6 +53,14 @@ const routes: Routes = [
|
|||
children: [],
|
||||
component: AddressComponent
|
||||
},
|
||||
{
|
||||
path: 'asset/:id',
|
||||
component: AssetComponent
|
||||
},
|
||||
{
|
||||
path: 'assets',
|
||||
component: AssetsComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@ import { SeoService } from './services/seo.service';
|
|||
import { MempoolGraphComponent } from './components/mempool-graph/mempool-graph.component';
|
||||
import { AssetComponent } from './components/asset/asset.component';
|
||||
import { ScriptpubkeyTypePipe } from './pipes/scriptpubkey-type-pipe/scriptpubkey-type.pipe';
|
||||
import { AssetsComponent } from './assets/assets.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -84,6 +85,7 @@ import { ScriptpubkeyTypePipe } from './pipes/scriptpubkey-type-pipe/scriptpubke
|
|||
MempoolGraphComponent,
|
||||
AssetComponent,
|
||||
ScriptpubkeyTypePipe,
|
||||
AssetsComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
|
61
frontend/src/app/assets/assets.component.html
Normal file
61
frontend/src/app/assets/assets.component.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
<div class="container-xl">
|
||||
<h1 style="float: left;">Registered assets</h1>
|
||||
<br>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<ng-template [ngIf]="!isLoading && !error">
|
||||
<table class="table table-borderless table-striped">
|
||||
<thead>
|
||||
<th style="td-name">Name</th>
|
||||
<th>Ticker</th>
|
||||
<th class="d-none d-md-block">Issuer domain</th>
|
||||
<th>Asset ID</th>
|
||||
<th class="d-none d-lg-block">Issuance TX</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let asset of assets">
|
||||
<td class="td-name">{{ asset.name }}</td>
|
||||
<td>{{ asset.ticker }}</td>
|
||||
<td class="d-none d-md-block"><a *ngIf="asset.entity" target="_blank" href="{{ 'http://' + asset.entity.domain }}">{{ asset.entity.domain }}</a></td>
|
||||
<td><a [routerLink]="['/asset/', asset.asset_id]">{{ asset.asset_id | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.asset_id"></app-clipboard></td>
|
||||
<td class="d-none d-lg-block"><ng-template [ngIf]="asset.issuance_txin"><a [routerLink]="['/tx/', asset.issuance_txin.txid]">{{ asset.issuance_txin.txid | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.issuance_txin.txid"></app-clipboard></ng-template></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngIf]="isLoading && !error">
|
||||
|
||||
<table class="table table-borderless table-striped">
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Ticker</th>
|
||||
<th>Issuer domain</th>
|
||||
<th>Asset ID</th>
|
||||
<th>Issuance TX</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let dummy of [0,0,0]">
|
||||
<td><span class="skeleton-loader"></span></td>
|
||||
<td><span class="skeleton-loader"></span></td>
|
||||
<td><span class="skeleton-loader"></span></td>
|
||||
<td><span class="skeleton-loader"></span></td>
|
||||
<td><span class="skeleton-loader"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</ng-template>
|
||||
|
||||
<ng-template [ngIf]="error">
|
||||
<div class="text-center">
|
||||
Error loading assets data.
|
||||
<br>
|
||||
<i>{{ error.error }}</i>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
6
frontend/src/app/assets/assets.component.scss
Normal file
6
frontend/src/app/assets/assets.component.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
.td-name {
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
25
frontend/src/app/assets/assets.component.spec.ts
Normal file
25
frontend/src/app/assets/assets.component.spec.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AssetsComponent } from './assets.component';
|
||||
|
||||
describe('AssetsComponent', () => {
|
||||
let component: AssetsComponent;
|
||||
let fixture: ComponentFixture<AssetsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AssetsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AssetsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
41
frontend/src/app/assets/assets.component.ts
Normal file
41
frontend/src/app/assets/assets.component.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { AssetsService } from '../services/assets.service';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-assets',
|
||||
templateUrl: './assets.component.html',
|
||||
styleUrls: ['./assets.component.scss']
|
||||
})
|
||||
export class AssetsComponent implements OnInit {
|
||||
nativeAssetId = environment.nativeAssetId;
|
||||
|
||||
isLoading = true;
|
||||
error: any;
|
||||
|
||||
assets: any;
|
||||
|
||||
constructor(
|
||||
private assetsService: AssetsService,
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.assetsService.getAssetsJson$()
|
||||
.subscribe((assets) => {
|
||||
this.assets = Object.values(assets);
|
||||
this.assets.push({
|
||||
name: 'Liquid Bitcoin',
|
||||
ticker: 'L-BTC',
|
||||
asset_id: this.nativeAssetId,
|
||||
});
|
||||
this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
||||
this.isLoading = false;
|
||||
},
|
||||
(error) => {
|
||||
console.log(error);
|
||||
this.error = error;
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -24,11 +24,11 @@
|
|||
<td>Precision</td>
|
||||
<td>{{ assetContract[3] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr *ngIf="!isNativeAsset">
|
||||
<td>Issuer</td>
|
||||
<td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr *ngIf="!isNativeAsset">
|
||||
<td>Issuance tx</td>
|
||||
<td><a [routerLink]="['/tx/', asset.issuance_txin.txid]">{{ asset.issuance_txin.txid | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.issuance_txin.txid"></app-clipboard></td>
|
||||
</tr>
|
||||
|
@ -38,17 +38,29 @@
|
|||
<div class="col">
|
||||
<table class="table table-borderless table-striped">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Circulating amount</td>
|
||||
<td>{{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + assetContract[3] }}</td>
|
||||
<tr *ngIf="isNativeAsset">
|
||||
<td>Pegged in</td>
|
||||
<td>{{ asset.chain_stats.peg_in_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr *ngIf="isNativeAsset">
|
||||
<td>Pegged out</td>
|
||||
<td>{{ asset.chain_stats.peg_out_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="!isNativeAsset">
|
||||
<td>Issued amount</td>
|
||||
<td>{{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + assetContract[3] }}</td>
|
||||
<td>{{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Burned amount</td>
|
||||
<td>{{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + assetContract[3] }}</td>
|
||||
<td>{{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="!isNativeAsset">
|
||||
<td>Circulating amount</td>
|
||||
<td>{{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="isNativeAsset">
|
||||
<td>Circulating amount</td>
|
||||
<td>{{ (asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount) / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -59,7 +71,7 @@
|
|||
|
||||
<br>
|
||||
|
||||
<h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} of </ng-template>{{ txCount | number }} transactions</h2>
|
||||
<h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} of </ng-template>{{ txCount | number }} <ng-template [ngIf]="isNativeAsset" [ngIfElse]="defaultAsset">Peg In/Out and Burn Transactions</ng-template><ng-template #defaultAsset>In/Out and Burn Transactions</ng-template></h2>
|
||||
|
||||
<app-transactions-list [transactions]="transactions" [showConfirmations]="true" (loadMore)="loadMore()"></app-transactions-list>
|
||||
|
||||
|
@ -86,8 +98,7 @@
|
|||
|
||||
<ng-template [ngIf]="isLoadingAsset && !error">
|
||||
|
||||
<div class="box">
|
||||
<div class="row">
|
||||
<ng-template #loadingTmpl>
|
||||
<div class="col">
|
||||
<table class="table table-borderless table-striped">
|
||||
<tbody>
|
||||
|
@ -103,9 +114,12 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col">
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="row">
|
||||
<ng-container *ngTemplateOutlet="loadingTmpl"></ng-container>
|
||||
<ng-container *ngTemplateOutlet="loadingTmpl"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import { AssetsService } from 'src/app/services/assets.service';
|
|||
})
|
||||
export class AssetComponent implements OnInit, OnDestroy {
|
||||
network = environment.network;
|
||||
nativeAssetId = environment.nativeAssetId;
|
||||
|
||||
asset: Asset;
|
||||
assetContract: any;
|
||||
|
@ -26,6 +27,7 @@ export class AssetComponent implements OnInit, OnDestroy {
|
|||
isLoadingAsset = true;
|
||||
transactions: Transaction[];
|
||||
isLoadingTransactions = true;
|
||||
isNativeAsset = false;
|
||||
error: any;
|
||||
mainSubscription: Subscription;
|
||||
|
||||
|
@ -94,6 +96,8 @@ export class AssetComponent implements OnInit, OnDestroy {
|
|||
switchMap(([asset, assetsData]) => {
|
||||
this.asset = asset;
|
||||
this.assetContract = assetsData[this.asset.asset_id];
|
||||
console.log(this.assetContract);
|
||||
this.isNativeAsset = asset.asset_id === this.nativeAssetId;
|
||||
this.updateChainStats();
|
||||
this.websocketService.startTrackAsset(asset.asset_id);
|
||||
this.isLoadingAsset = false;
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/tv" (click)="collapse()">TV view <img src="./assets/expand.png" width="15"/></a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/assets" (click)="collapse()">Assets</a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/contributors" (click)="collapse()">Contributors</a>
|
||||
</li>
|
||||
|
|
|
@ -28,11 +28,10 @@
|
|||
</ng-template>
|
||||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<ng-template [ngIf]="vin.is_coinbase" [ngIfElse]="regularVin">
|
||||
Coinbase (Newly Generated Coins)
|
||||
</ng-template>
|
||||
<ng-template #regularVin>
|
||||
<div [ngSwitch]="true">
|
||||
<ng-container *ngSwitchCase="vin.is_coinbase">Coinbase (Newly Generated Coins)</ng-container>
|
||||
<ng-container *ngSwitchCase="vin.is_pegin">PEG IN</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<a [routerLink]="['/address/', vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
|
||||
<span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
|
||||
<span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 42 }}</span>
|
||||
|
@ -40,7 +39,7 @@
|
|||
<div>
|
||||
<app-address-labels [vin]="vin"></app-address-labels>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right nowrap">
|
||||
|
@ -66,8 +65,13 @@
|
|||
<span class="d-none d-lg-block">{{ vout.scriptpubkey_address | shortenString : 42 }}</span>
|
||||
</a>
|
||||
<ng-template #scriptpubkey_type>
|
||||
<ng-template [ngIf]="vout.pegout" [ngIfElse]="defaultscriptpubkey_type">
|
||||
PEG OUT
|
||||
</ng-template>
|
||||
<ng-template #defaultscriptpubkey_type>
|
||||
{{ vout.scriptpubkey_type | scriptpubkeyType }}
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</td>
|
||||
<td class="text-right nowrap">
|
||||
<ng-template [ngIf]="vout.asset && vout.scriptpubkey_type === 'op_return' && vout.asset !== nativeAssetId" [ngIfElse]="defaultOutput">
|
||||
|
|
|
@ -37,6 +37,7 @@ export interface Vin {
|
|||
sequence: any;
|
||||
witness?: string[];
|
||||
inner_witnessscript_asm?: string;
|
||||
is_pegin?: boolean;
|
||||
}
|
||||
|
||||
export interface Vout {
|
||||
|
@ -45,7 +46,16 @@ export interface Vout {
|
|||
scriptpubkey_type: string;
|
||||
scriptpubkey_address: string;
|
||||
value: number;
|
||||
valuecommitment?: number;
|
||||
asset?: string;
|
||||
pegout?: Pegout;
|
||||
}
|
||||
|
||||
interface Pegout {
|
||||
genesis_hash: string;
|
||||
scriptpubkey: string;
|
||||
scriptpubkey_asm: string;
|
||||
scriptpubkey_addres: string;
|
||||
}
|
||||
|
||||
export interface Status {
|
||||
|
|
|
@ -22,8 +22,11 @@ export class AssetsService {
|
|||
getAssetsMinimalJson$() {
|
||||
this.httpClient.get('/assets/assets.minimal.json')
|
||||
.subscribe((data) => {
|
||||
console.log(data);
|
||||
this.assetsMinimal$.next(data);
|
||||
});
|
||||
}
|
||||
|
||||
getAssetsJson$() {
|
||||
return this.httpClient.get('/assets/assets.json');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,3 @@ console.log('Downloading assets');
|
|||
download(PATH + 'assets.json', 'https://raw.githubusercontent.com/Blockstream/asset_registry_db/master/index.json');
|
||||
console.log('Downloading assets minimal');
|
||||
download(PATH + 'assets.minimal.json', 'https://raw.githubusercontent.com/Blockstream/asset_registry_db/master/index.minimal.json');
|
||||
console.log('Downloading asset icons');
|
||||
download(PATH + 'asset.icons.json', 'https://raw.githubusercontent.com/Blockstream/asset_registry_db/master/icons.json');
|
||||
|
|
Loading…
Add table
Reference in a new issue