diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 1b30e0d21..71d73ab97 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -44,7 +44,7 @@ import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faAngleDown, faAngleUp, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, - faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv } from '@fortawesome/free-solid-svg-icons'; + faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faAngleDoubleUp } from '@fortawesome/free-solid-svg-icons'; import { ApiDocsComponent } from './components/api-docs/api-docs.component'; import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component'; import { StorageService } from './services/storage.service'; @@ -125,5 +125,7 @@ export class AppModule { library.addIcons(faAngleDown); library.addIcons(faAngleUp); library.addIcons(faExchangeAlt); + library.addIcons(faAngleDoubleUp); + library.addIcons(faAngleDoubleDown); } } diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 7938429fa..e4a53a2cf 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -137,6 +137,57 @@ + +
+ +

CPFP

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeTXIDVirtual sizeFee rate
Descendant + + {{ cpfpInfo.bestDescendant.txid | shortenString : 10 }} + {{ cpfpInfo.bestDescendant.txid }} + + {{ cpfpInfo.bestDescendant.weight / 4 | vbytes: 2 }}{{ cpfpInfo.bestDescendant.fee / (cpfpInfo.bestDescendant.weight / 4) | number : '1.1-1' }} sat/vB
Ancestor + {{ cpfpTx.txid | shortenString : 10 }} + {{ cpfpTx.txid }} + + {{ cpfpTx.weight / 4 | vbytes: 2 }}{{ roundToOneDecimal(cpfpTx) | number : '1.1-1' }} sat/vB
+
+
+

Inputs & Outputs

@@ -279,26 +330,25 @@ {{ tx.fee | number }} sat () - Fee per vByte + Fee rate - {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB + {{ tx.feePerVsize }} sat/vB   - + - - Effective fee + + Effective fee rate {{ tx.effectiveFeePerVsize | number : '1.1-1' }} sat/vB -   - + + - - \ No newline at end of file + diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss index 18ebaf55b..77b4ccf49 100644 --- a/frontend/src/app/components/transaction/transaction.component.scss +++ b/frontend/src/app/components/transaction/transaction.component.scss @@ -26,4 +26,21 @@ h1 { margin-bottom: 0; +} + +.badge { + position: relative; + top: -1px; +} + +.btn-small-height { + line-height: 1.1; +} + +.arrow-green { + color: #1a9436; +} + +.arrow-red { + color: #dc3545; } \ No newline at end of file diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index d0c396959..e551b71b6 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -9,6 +9,7 @@ import { WebsocketService } from '../../services/websocket.service'; import { AudioService } from 'src/app/services/audio.service'; import { ApiService } from 'src/app/services/api.service'; import { SeoService } from 'src/app/services/seo.service'; +import { CpfpInfo } from 'src/app/interfaces/node-api.interface'; @Component({ selector: 'app-transaction', @@ -27,6 +28,8 @@ export class TransactionComponent implements OnInit, OnDestroy { transactionTime = -1; subscription: Subscription; rbfTransaction: undefined | Transaction; + cpfpInfo: CpfpInfo | null; + showCpfpDetails = false; constructor( private route: ActivatedRoute, @@ -77,6 +80,7 @@ export class TransactionComponent implements OnInit, OnDestroy { if (tx.fee === undefined) { this.tx.fee = 0; } + this.tx.feePerVsize = +(tx.fee / (tx.weight / 4)).toFixed(1); this.isLoadingTx = false; this.error = undefined; this.waitingForTransaction = false; @@ -97,6 +101,11 @@ export class TransactionComponent implements OnInit, OnDestroy { } else { if (tx.effectiveFeePerVsize) { this.stateService.markBlock$.next({ txFeePerVSize: tx.effectiveFeePerVsize }); + this.cpfpInfo = { + ancestors: tx.ancestors, + bestDescendant: tx.bestDescendant, + }; + tx.effectiveFeePerVsize = +(tx.effectiveFeePerVsize).toFixed(1); } else { this.apiService.getCpfpinfo$(this.tx.txid) .subscribe((cpfpInfo) => { @@ -108,9 +117,10 @@ export class TransactionComponent implements OnInit, OnDestroy { totalFees += cpfpInfo.bestDescendant.fee; } - const effectiveFeePerVsize = totalFees / (totalWeight / 4); + const effectiveFeePerVsize = +(totalFees / (totalWeight / 4)).toFixed(1); this.tx.effectiveFeePerVsize = effectiveFeePerVsize; this.stateService.markBlock$.next({ txFeePerVSize: effectiveFeePerVsize }); + this.cpfpInfo = cpfpInfo; }); } } @@ -183,6 +193,8 @@ export class TransactionComponent implements OnInit, OnDestroy { this.isLoadingTx = true; this.rbfTransaction = undefined; this.transactionTime = -1; + this.cpfpInfo = null; + this.showCpfpDetails = false; document.body.scrollTo(0, 0); this.leaveTransaction(); } @@ -192,6 +204,10 @@ export class TransactionComponent implements OnInit, OnDestroy { this.stateService.markBlock$.next({}); } + roundToOneDecimal(cpfpTx: any): number { + return +(cpfpTx.fee / (cpfpTx.weight / 4)).toFixed(1); + } + ngOnDestroy() { this.subscription.unsubscribe(); this.leaveTransaction(); diff --git a/frontend/src/app/interfaces/electrs.interface.ts b/frontend/src/app/interfaces/electrs.interface.ts index 1ea0184ae..b09b3fd6d 100644 --- a/frontend/src/app/interfaces/electrs.interface.ts +++ b/frontend/src/app/interfaces/electrs.interface.ts @@ -11,7 +11,24 @@ export interface Transaction { // Custom properties firstSeen?: number; + feePerVsize?: number; effectiveFeePerVsize?: number; + ancestors?: Ancestor[]; + bestDescendant?: BestDescendant | null; + cpfpChecked?: boolean; + deleteAfter?: number; +} + +interface Ancestor { + txid: string; + weight: number; + fee: number; +} + +interface BestDescendant { + txid: string; + weight: number; + fee: number; } export interface Recent { diff --git a/frontend/src/locale/messages.xlf b/frontend/src/locale/messages.xlf index cc70645cc..52d5f6439 100644 --- a/frontend/src/locale/messages.xlf +++ b/frontend/src/locale/messages.xlf @@ -6,7 +6,7 @@ Transaction: src/app/components/transaction/transaction.component.ts - 48 + 51 src/app/bisq/bisq-transaction/bisq-transaction.component.ts @@ -97,7 +97,7 @@ Inputs & Outputs src/app/components/transaction/transaction.component.html - 142 + 193 src/app/bisq/bisq-transaction/bisq-transaction.component.html @@ -114,7 +114,7 @@ Details src/app/components/transaction/transaction.component.html - 144 + 195 Transaction Details transaction.details @@ -123,11 +123,11 @@ Details src/app/components/transaction/transaction.component.html - 150 + 201 src/app/components/transaction/transaction.component.html - 226 + 277 src/app/bisq/bisq-transaction/bisq-transaction.component.html @@ -143,7 +143,7 @@ Size src/app/components/transaction/transaction.component.html - 155 + 206 Transaction Size transaction.size @@ -152,7 +152,11 @@ Virtual size src/app/components/transaction/transaction.component.html - 159 + 210 + + + src/app/components/transaction/transaction.component.html + 150 Transaction Virtual Size transaction.vsize @@ -161,7 +165,7 @@ Weight src/app/components/transaction/transaction.component.html - 163 + 214 Transaction Weight transaction.weight @@ -262,116 +266,77 @@ Transaction ETA in several hours or more transaction.eta.in-several-hours - - Transaction not found. + + Type src/app/components/transaction/transaction.component.html - 251 + 148 - transaction.error.transaction-not-found + + src/app/components/transactions-list/transactions-list.component.html + 169 + + + src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html + 25 + + + src/app/bisq/bisq-transactions/bisq-transactions.component.html + 19 + + transactions-list.vout.scriptpubkey-type - - Waiting for it to appear in the mempool... + + TXID src/app/components/transaction/transaction.component.html - 252 + 149 - transaction.error.waiting-for-it-to-appear + + src/app/dashboard/dashboard.component.html + 107 + + dashboard.latest-transactions.txid - - In ~ minutes + + Fee rate src/app/components/transaction/transaction.component.html - 267 + 151 - src/app/components/mempool-blocks/mempool-blocks.component.html - 41 + src/app/components/transaction/transaction.component.html + 333 - Block Frequency (plural) - mempool-blocks.eta-of-next-block-plural + Transaction fee rate + transaction.fee-rate - - In ~ minute + + Descendant src/app/components/transaction/transaction.component.html - 269 + 158 - - src/app/components/mempool-blocks/mempool-blocks.component.html - 43 - - Block Frequency - mempool-blocks.eta-of-next-block - - - block - - src/app/components/transaction/transaction.component.html - 271 - - - src/app/components/footer/footer.component.html - 22 - - shared.block - - - blocks - - src/app/components/transaction/transaction.component.html - 272 - - - src/app/components/mempool-blocks/mempool-blocks.component.html - 30 - - - src/app/components/footer/footer.component.html - 23 - - shared.blocks - - - Fee - - src/app/components/transaction/transaction.component.html - 278 - - Transaction fee - transaction.fee - - - sat - - src/app/components/transaction/transaction.component.html - 279 - - Transaction Fee sat - transaction.fee.sat - - - Fee per vByte - - src/app/components/transaction/transaction.component.html - 282 - - - src/app/bisq/bisq-transaction/bisq-transaction.component.html - 62 - - Transaction fee - transaction.fee-per-vbyte + Descendant + transaction.descendant sat/vB src/app/components/transaction/transaction.component.html - 284 + 166 src/app/components/transaction/transaction.component.html - 294 + 179 + + + src/app/components/transaction/transaction.component.html + 335 + + + src/app/components/transaction/transaction.component.html + 345 src/app/components/transactions-list/transactions-list.component.html @@ -428,14 +393,111 @@ sat/vB shared.sat-vbyte - - Effective fee + + Ancestor src/app/components/transaction/transaction.component.html - 292 + 172 - Effective transaction fee - transaction.effective-fee + Transaction Ancestor + transaction.ancestor + + + Transaction not found. + + src/app/components/transaction/transaction.component.html + 302 + + transaction.error.transaction-not-found + + + Waiting for it to appear in the mempool... + + src/app/components/transaction/transaction.component.html + 303 + + transaction.error.waiting-for-it-to-appear + + + In ~ minutes + + src/app/components/transaction/transaction.component.html + 318 + + + src/app/components/mempool-blocks/mempool-blocks.component.html + 41 + + Block Frequency (plural) + mempool-blocks.eta-of-next-block-plural + + + In ~ minute + + src/app/components/transaction/transaction.component.html + 320 + + + src/app/components/mempool-blocks/mempool-blocks.component.html + 43 + + Block Frequency + mempool-blocks.eta-of-next-block + + + block + + src/app/components/transaction/transaction.component.html + 322 + + + src/app/components/footer/footer.component.html + 22 + + shared.block + + + blocks + + src/app/components/transaction/transaction.component.html + 323 + + + src/app/components/mempool-blocks/mempool-blocks.component.html + 30 + + + src/app/components/footer/footer.component.html + 23 + + shared.blocks + + + Fee + + src/app/components/transaction/transaction.component.html + 329 + + Transaction fee + transaction.fee + + + sat + + src/app/components/transaction/transaction.component.html + 330 + + Transaction Fee sat + transaction.fee.sat + + + Effective fee rate + + src/app/components/transaction/transaction.component.html + 343 + + Effective transaction fee rate + transaction.effective-fee-rate Coinbase @@ -557,22 +619,6 @@ ScriptPubKey (HEX) transactions-list.scriptpubkey.hex - - Type - - src/app/components/transactions-list/transactions-list.component.html - 169 - - - src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html - 25 - - - src/app/bisq/bisq-transactions/bisq-transactions.component.html - 19 - - transactions-list.vout.scriptpubkey-type - data @@ -1728,14 +1774,6 @@ dashboard.latest-transactions - - TXID - - src/app/dashboard/dashboard.component.html - 107 - - dashboard.latest-transactions.txid - Amount @@ -2354,16 +2392,12 @@ TX Fee Rating is Optimal tx-fee-rating.optimal - - Only ~ sat/vB was needed to get into this block + + Only ~ sat/vB was needed to get into this block src/app/components/tx-fee-rating/tx-fee-rating.component.html 2 - - src/app/components/tx-fee-rating/tx-fee-rating.component.html - 3 - tx-fee-rating.warning-tooltip @@ -2375,6 +2409,14 @@ TX Fee Rating is Warning tx-fee-rating.overpaid.warning + + Only ~ sat/vB was needed to get into this block + + src/app/components/tx-fee-rating/tx-fee-rating.component.html + 3 + + tx-fee-rating.danger-tooltip + Overpaid x @@ -2691,6 +2733,15 @@ Transaction Previous Hash block.previous_hash + + Fee per vByte + + src/app/bisq/bisq-transaction/bisq-transaction.component.html + 62 + + Transaction fee + transaction.fee-per-vbyte + Filter