Merge pull request #3601 from mempool/mononaut/fix-liquid-asset-diagram

Fix broken tx diagram for non-LBTC liquid assets
This commit is contained in:
softsimon 2023-04-03 14:39:38 +09:00 committed by GitHub
commit 41a93af89e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 13 deletions

View File

@ -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>&nbsp; #{{ 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>

View File

@ -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;

View File

@ -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') {