Merge branch 'master' into hunicus/mynode-casing
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
</ng-template>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-fee-span'" class="fee-span"
|
||||
*ngIf="block?.extras?.feeRange; else emptyfeespan">
|
||||
{{ block?.extras?.feeRange?.[1] | number:feeRounding }} - {{
|
||||
{{ block?.extras?.feeRange?.[0] | number:feeRounding }} - {{
|
||||
block?.extras?.feeRange[block?.extras?.feeRange?.length - 1] | number:feeRounding }} <ng-container
|
||||
i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -62,6 +62,21 @@
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div *ngIf="network.val === 'testnet' || network.val === 'signet' || network.val === 'liquidtestnet'">
|
||||
<div class="container p-lg-0 pb-0" style="max-width: 100%; margin-top: 7px" *ngIf="storageService.getValue('hideWarning') !== 'hidden'">
|
||||
<div class="alert alert-danger mb-0 text-center">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<fa-icon class="between-arrow mr-1" [icon]="['fas', 'exclamation-triangle']" [fixedWidth]="true"></fa-icon>
|
||||
<span i18n="warning-testnet">This is a test network. Coins have no value</span>
|
||||
<fa-icon class="between-arrow ml-1" [icon]="['fas', 'exclamation-triangle']" [fixedWidth]="true"></fa-icon>
|
||||
</div>
|
||||
<button type="button" class="close" (click)="dismissWarning()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -192,4 +192,19 @@ nav {
|
||||
margin: 33px 0px 0px -19px;
|
||||
font-size: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
color: black;
|
||||
right: 10px;
|
||||
top: 17px;
|
||||
@media (max-width: 620px) {
|
||||
right: 10px;
|
||||
top: 0px;
|
||||
};
|
||||
@media (min-width: 992px) {
|
||||
right: 10px;
|
||||
top: 13px;
|
||||
};
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { Observable, merge, of } from 'rxjs';
|
||||
import { LanguageService } from '../../services/language.service';
|
||||
import { EnterpriseService } from '../../services/enterprise.service';
|
||||
import { NavigationService } from '../../services/navigation.service';
|
||||
import { StorageService } from '../../services/storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-master-page',
|
||||
@@ -26,6 +27,7 @@ export class MasterPageComponent implements OnInit {
|
||||
private languageService: LanguageService,
|
||||
private enterpriseService: EnterpriseService,
|
||||
private navigationService: NavigationService,
|
||||
public storageService: StorageService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
@@ -46,4 +48,8 @@ export class MasterPageComponent implements OnInit {
|
||||
onResize(event: any) {
|
||||
this.isMobile = window.innerWidth <= 767.98;
|
||||
}
|
||||
|
||||
dismissWarning() {
|
||||
this.storageService.setValue('hideWarning', 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
</div>
|
||||
<div *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" class="features">
|
||||
<app-tx-features [tx]="tx"></app-tx-features>
|
||||
<span *ngIf="cpfpInfo && (cpfpInfo.bestDescendant || cpfpInfo.descendants.length)" class="badge badge-primary mr-1">
|
||||
CPFP
|
||||
</span>
|
||||
<span *ngIf="cpfpInfo && !cpfpInfo.bestDescendant && !cpfpInfo.descendants.length && cpfpInfo.ancestors.length" class="badge badge-info mr-1">
|
||||
<span *ngIf="cpfpInfo && (cpfpInfo?.bestDescendant || cpfpInfo?.descendants?.length || cpfpInfo?.ancestors?.length)" class="badge badge-primary ml-1 mr-1">
|
||||
CPFP
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<div infiniteScroll [alwaysCallback]="true" [infiniteScrollDistance]="2" [infiniteScrollUpDistance]="1.5" [infiniteScrollThrottle]="50" (scrolled)="onScroll()">
|
||||
|
||||
<ng-container *ngFor="let tx of transactions; let i = index; trackBy: trackByFn">
|
||||
<div *ngIf="!transactionPage" class="header-bg box tx-page-container">
|
||||
<a class="tx-link" [routerLink]="['/tx/' | relativeUrl, tx.txid]">
|
||||
@@ -11,7 +13,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-bg box" infiniteScroll [alwaysCallback]="true" [infiniteScrollDistance]="2" [infiniteScrollUpDistance]="1.5" [infiniteScrollThrottle]="50" (scrolled)="onScroll()" [attr.data-cy]="'tx-' + i">
|
||||
<div class="header-bg box">
|
||||
|
||||
<div *ngIf="errorUnblinded" class="error-unblinded">{{ errorUnblinded }}</div>
|
||||
<div class="row">
|
||||
@@ -321,6 +323,8 @@
|
||||
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
<ng-template #assetBox let-item>
|
||||
{{ item.value / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }}
|
||||
<br />
|
||||
|
||||
@@ -182,14 +182,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
onScroll(): void {
|
||||
const scrollHeight = document.body.scrollHeight;
|
||||
const scrollTop = document.documentElement.scrollTop;
|
||||
if (scrollHeight > 0) {
|
||||
const percentageScrolled = scrollTop * 100 / scrollHeight;
|
||||
if (percentageScrolled > 50) {
|
||||
this.loadMore.emit();
|
||||
}
|
||||
}
|
||||
this.loadMore.emit();
|
||||
}
|
||||
|
||||
haveBlindedOutputValues(tx: Transaction): boolean {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<ng-template #pegout>
|
||||
<ng-container *ngIf="line.pegout; else normal">
|
||||
<p *ngIf="!isConnector">Peg Out</p>
|
||||
<p *ngIf="line.value != null"><app-amount [satoshis]="line.value"></app-amount></p>
|
||||
<p *ngIf="line.displayValue != null"><app-amount [satoshis]="line.displayValue"></app-amount></p>
|
||||
<p class="address">
|
||||
<app-truncate [text]="line.pegout"></app-truncate>
|
||||
</p>
|
||||
@@ -55,18 +55,18 @@
|
||||
<p *ngSwitchCase="'output'"><span i18n="transaction.input">Input</span> #{{ line.vin + 1 }}</p>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<p *ngIf="line.value == null && line.confidential" i18n="shared.confidential">Confidential</p>
|
||||
<p *ngIf="line.value != null">
|
||||
<p *ngIf="line.displayValue == null && line.confidential" i18n="shared.confidential">Confidential</p>
|
||||
<p *ngIf="line.displayValue != null">
|
||||
<ng-template [ngIf]="line.asset && line.asset !== nativeAssetId" [ngIfElse]="defaultOutput">
|
||||
<div *ngIf="assetsMinimal && assetsMinimal[line.asset] else assetNotFound">
|
||||
<ng-container *ngTemplateOutlet="assetBox; context:{ $implicit: line }"></ng-container>
|
||||
</div>
|
||||
<ng-template #assetNotFound>
|
||||
{{ line.value }} <span class="symbol">{{ line.asset | slice : 0 : 7 }}</span>
|
||||
{{ line.displayValue }} <span class="symbol">{{ line.asset | slice : 0 : 7 }}</span>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
<ng-template #defaultOutput>
|
||||
<app-amount [blockConversion]="blockConversion" [satoshis]="line.value"></app-amount>
|
||||
<app-amount [blockConversion]="blockConversion" [satoshis]="line.displayValue"></app-amount>
|
||||
</ng-template>
|
||||
</p>
|
||||
<p *ngIf="line.type !== 'fee' && line.address" class="address">
|
||||
@@ -76,5 +76,5 @@
|
||||
</div>
|
||||
|
||||
<ng-template #assetBox let-item>
|
||||
{{ item.value / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} <span class="symbol">{{ assetsMinimal[item.asset][1] }}</span>
|
||||
{{ item.displayValue / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} <span class="symbol">{{ assetsMinimal[item.asset][1] }}</span>
|
||||
</ng-template>
|
||||
@@ -7,6 +7,7 @@ import { environment } from '../../../environments/environment';
|
||||
interface Xput {
|
||||
type: 'input' | 'output' | 'fee';
|
||||
value?: number;
|
||||
displayValue?: number;
|
||||
index?: number;
|
||||
txid?: string;
|
||||
vin?: number;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Component, OnInit, Input, OnChanges, HostListener, Inject, LOCALE_ID } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { Outspend, Transaction } from '../../interfaces/electrs.interface';
|
||||
import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplaySubject, merge, Subscription, of } from 'rxjs';
|
||||
import { tap, switchMap } from 'rxjs/operators';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||
import { AssetsService } from '../../services/assets.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
interface SvgLine {
|
||||
path: string;
|
||||
@@ -20,6 +21,7 @@ interface SvgLine {
|
||||
interface Xput {
|
||||
type: 'input' | 'output' | 'fee';
|
||||
value?: number;
|
||||
displayValue?: number;
|
||||
index?: number;
|
||||
txid?: string;
|
||||
vin?: number;
|
||||
@@ -74,6 +76,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
zeroValueThickness = 20;
|
||||
hasLine: boolean;
|
||||
assetsMinimal: any;
|
||||
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
|
||||
|
||||
outspendsSubscription: Subscription;
|
||||
refreshOutspends$: ReplaySubject<string> = new ReplaySubject();
|
||||
@@ -167,7 +170,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
let voutWithFee = this.tx.vout.map((v, i) => {
|
||||
return {
|
||||
type: v.scriptpubkey_type === 'fee' ? 'fee' : 'output',
|
||||
value: v?.value,
|
||||
value: this.getOutputValue(v),
|
||||
displayValue: v?.value,
|
||||
address: v?.scriptpubkey_address || v?.scriptpubkey_type?.toUpperCase(),
|
||||
index: i,
|
||||
pegout: v?.pegout?.scriptpubkey_address,
|
||||
@@ -185,7 +189,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
let truncatedInputs = this.tx.vin.map((v, i) => {
|
||||
return {
|
||||
type: 'input',
|
||||
value: v?.prevout?.value || (v?.is_coinbase && !totalValue ? 0 : undefined),
|
||||
value: (v?.is_coinbase && !totalValue ? 0 : this.getInputValue(v)),
|
||||
displayValue: v?.prevout?.value,
|
||||
txid: v.txid,
|
||||
vout: v.vout,
|
||||
address: v?.prevout?.scriptpubkey_address || v?.prevout?.scriptpubkey_type?.toUpperCase(),
|
||||
@@ -229,14 +234,14 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
calcTotalValue(tx: Transaction): number {
|
||||
const totalOutput = this.tx.vout.reduce((acc, v) => (v.value == null ? 0 : v.value) + acc, 0);
|
||||
let totalOutput = this.tx.vout.reduce((acc, v) => (this.getOutputValue(v) || 0) + acc, 0);
|
||||
// simple sum of outputs + fee for bitcoin
|
||||
if (!this.isLiquid) {
|
||||
return this.tx.fee ? totalOutput + this.tx.fee : totalOutput;
|
||||
} else {
|
||||
const totalInput = this.tx.vin.reduce((acc, v) => (v?.prevout?.value == null ? 0 : v.prevout.value) + acc, 0);
|
||||
const confidentialInputCount = this.tx.vin.reduce((acc, v) => acc + (v?.prevout?.value == null ? 1 : 0), 0);
|
||||
const confidentialOutputCount = this.tx.vout.reduce((acc, v) => acc + (v.value == null ? 1 : 0), 0);
|
||||
const totalInput = this.tx.vin.reduce((acc, v) => (this.getInputValue(v) || 0) + acc, 0);
|
||||
const confidentialInputCount = this.tx.vin.reduce((acc, v) => acc + (this.isUnknownInputValue(v) ? 1 : 0), 0);
|
||||
const confidentialOutputCount = this.tx.vout.reduce((acc, v) => acc + (this.isUnknownOutputValue(v) ? 1 : 0), 0);
|
||||
|
||||
// if there are unknowns on both sides, the total is indeterminate, so we'll just fudge it
|
||||
if (confidentialInputCount && confidentialOutputCount) {
|
||||
@@ -456,6 +461,34 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
getOutputValue(v: Vout): number | void {
|
||||
if (!v) {
|
||||
return null;
|
||||
} else if (this.isLiquid && v.asset !== this.nativeAssetId) {
|
||||
return null;
|
||||
} else {
|
||||
return v.value;
|
||||
}
|
||||
}
|
||||
|
||||
getInputValue(v: Vin): number | void {
|
||||
if (!v?.prevout) {
|
||||
return null;
|
||||
} else if (this.isLiquid && v.prevout.asset !== this.nativeAssetId) {
|
||||
return null;
|
||||
} else {
|
||||
return v.prevout.value;
|
||||
}
|
||||
}
|
||||
|
||||
isUnknownInputValue(v: Vin): boolean {
|
||||
return v?.prevout?.value == null || this.isLiquid && v?.prevout?.asset !== this.nativeAssetId;
|
||||
}
|
||||
|
||||
isUnknownOutputValue(v: Vout): boolean {
|
||||
return v?.value == null || this.isLiquid && v?.asset !== this.nativeAssetId;
|
||||
}
|
||||
|
||||
@HostListener('pointermove', ['$event'])
|
||||
onPointerMove(event) {
|
||||
if (this.dir === 'rtl') {
|
||||
|
||||
Reference in New Issue
Block a user