- ETA
+ ETA
= 7" [ngIfElse]="belowBlockLimit">
-
- In several hours (or more)
- Accelerate
+
+ In several hours (or more)
+
+ Accelerate
+
@@ -109,9 +144,11 @@
-
-
- Accelerate
+
+
+
+ Accelerate
+
diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss
index 5bef401d7..45357471a 100644
--- a/frontend/src/app/components/transaction/transaction.component.scss
+++ b/frontend/src/app/components/transaction/transaction.component.scss
@@ -228,11 +228,15 @@
}
}
+.link.accelerator {
+ cursor: pointer;
+}
+
.accelerate {
align-self: auto;
margin-top: 3px;
+ margin-left: 10px;
@media (min-width: 850px) {
justify-self: start;
- margin-left: 0px;
}
}
\ 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 f1f3850e4..db200e9b1 100644
--- a/frontend/src/app/components/transaction/transaction.component.ts
+++ b/frontend/src/app/components/transaction/transaction.component.ts
@@ -19,6 +19,7 @@ import { WebsocketService } from '../../services/websocket.service';
import { AudioService } from '../../services/audio.service';
import { ApiService } from '../../services/api.service';
import { SeoService } from '../../services/seo.service';
+import { StorageService } from '../../services/storage.service';
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment } from '../../interfaces/node-api.interface';
import { LiquidUnblinding } from './liquid-ublinding';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
@@ -88,6 +89,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
rbfEnabled: boolean;
taprootEnabled: boolean;
hasEffectiveFeeRate: boolean;
+ accelerateCtaType: 'alert' | 'button' = 'alert';
+ acceleratorAvailable: boolean = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === '';
+ showAccelerationSummary = false;
@ViewChild('graphContainer')
graphContainer: ElementRef;
@@ -104,14 +108,20 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
private apiService: ApiService,
private seoService: SeoService,
private priceService: PriceService,
+ private storageService: StorageService
) {}
ngOnInit() {
this.websocketService.want(['blocks', 'mempool-blocks']);
this.stateService.networkChanged$.subscribe(
- (network) => (this.network = network)
+ (network) => {
+ this.network = network;
+ this.acceleratorAvailable = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === '';
+ }
);
+ this.accelerateCtaType = (this.storageService.getValue('accel-cta-type') as 'alert' | 'button') ?? 'alert';
+
this.setFlowEnabled();
this.flowPrefSubscription = this.stateService.hideFlow.subscribe((hide) => {
this.hideFlow = !!hide;
@@ -486,6 +496,19 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.setGraphSize();
}
+ dismissAccelAlert(): void {
+ this.storageService.setValue('accel-cta-type', 'button');
+ this.accelerateCtaType = 'button';
+ }
+
+ onAccelerateClicked(): void {
+ if (!this.txId) {
+ return;
+ }
+
+ this.showAccelerationSummary = true && this.acceleratorAvailable;
+ }
+
handleLoadElectrsTransactionError(error: any): Observable {
if (error.status === 404 && /^[a-fA-F0-9]{64}$/.test(this.txId)) {
this.websocketService.startMultiTrackTransaction(this.txId);
diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts
index cd1109da1..2d9077a97 100644
--- a/frontend/src/app/services/api.service.ts
+++ b/frontend/src/app/services/api.service.ts
@@ -388,4 +388,8 @@ export class ApiService {
getServicesBackendInfo$(): Observable {
return this.httpClient.get(`${SERVICES_API_PREFIX}/version`);
}
+
+ estimate$(txInput: string) {
+ return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' });
+ }
}
diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.html b/frontend/src/app/shared/components/confirmations/confirmations.component.html
index db3f1f38a..4ad3cb33a 100644
--- a/frontend/src/app/shared/components/confirmations/confirmations.component.html
+++ b/frontend/src/app/shared/components/confirmations/confirmations.component.html
@@ -1,19 +1,19 @@
-
+
{{ i }} confirmation
{{ i }} confirmations
- Confirmed
+ Confirmed
- Replaced
+ Replaced
- Removed
+ Removed
- Unconfirmed
+ Unconfirmed
\ No newline at end of file
diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.scss b/frontend/src/app/shared/components/confirmations/confirmations.component.scss
index e69de29bb..c8af7dd76 100644
--- a/frontend/src/app/shared/components/confirmations/confirmations.component.scss
+++ b/frontend/src/app/shared/components/confirmations/confirmations.component.scss
@@ -0,0 +1,4 @@
+.no-cursor {
+ cursor: default !important;
+ pointer-events: none;
+}
\ No newline at end of file
From fcecbe49677144328c743ba86b6d3fbd95305cc8 Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Sat, 26 Aug 2023 09:52:55 +0200
Subject: [PATCH 2/2] [tx] integrated accelerator
---
.../accelerate-preview.component.html | 231 ++++++++++++++++++
.../accelerate-preview.component.scss | 20 ++
.../accelerate-preview.component.ts | 163 +++++++++++-
.../transaction/transaction.component.html | 32 +--
.../transaction/transaction.component.scss | 59 +++--
.../transaction/transaction.component.ts | 7 +-
frontend/src/app/services/api.service.ts | 4 +
.../mempool-error.component.html | 2 +
.../mempool-error/mempool-error.component.ts | 47 ++++
frontend/src/app/shared/shared.module.ts | 8 +-
10 files changed, 519 insertions(+), 54 deletions(-)
create mode 100644 frontend/src/app/shared/components/mempool-error/mempool-error.component.html
create mode 100644 frontend/src/app/shared/components/mempool-error/mempool-error.component.ts
diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html
index e69de29bb..e2c6e3c22 100644
--- a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html
+++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.html
@@ -0,0 +1,231 @@
+
+
+
+ Transaction has now been submitted to mining pools for acceleration. You can track the progress
here .
+
+
+
+
+
+
+ 1">
+
+
+ This transactions is part of a CPFP tree. Fee rates (in sats/vb) are provided for your information. Change in the CPFP tree will lead to different fee rates values.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Next block market price
+
+
+ {{ estimate.targetFeeRate | number : '1.0-0' }} sat/vB
+
+
+
+
+ Currently estimated fee to get into next block
+
+
+
+ {{ estimate.nextBlockFee| number }} sats
+
+
+
+
+
+
+
+
+ Fees paid in-band
+
+
+ ~ {{ (estimate.txSummary.effectiveFee / estimate.txSummary.effectiveVsize) | number : '1.0-0' }} sat/vB
+
+
+
+
+ What you already paid when you made the transaction
+
+
+
+ {{ estimate.txSummary.effectiveFee | number }} sats
+
+
+
+
+
+
+
+
+ Extra fee required
+
+
+ {{ math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee) | number }} sats
+
+
+
+
+
+ Difference between the next block fee and your tx fee
+
+
+
+
+
+
+
+
How much more are you willing to pay at most to get into the next block?
+
+
+
+ The maximum extra transaction fee you're willing to pay to get into the next block. If the next block market price becomes too expensive for you, we will automatically cancel your acceleration request. Final charged fee may be smaller based on the fee market.
+
+
+
+
+
+
Acceleration summary
+
+
+
+
+
+
+
+ Your maximum tx fees
+
+
+ ~{{ ((estimate.txSummary.effectiveFee + userBid) / estimate.txSummary.effectiveVsize) | number : '1.0-0' }} sat/vB
+
+
+
+
+ The maximum extra transaction fee you're willing to pay
+
+
+
+ {{ userBid | number }} sats
+
+
+
+
+
+
+
+
+ Mempool Acceleratorâ„¢ fee
+
+
+ +{{ estimate.mempoolBaseFee + estimate.vsizeFee | number }} sats
+
+
+
+
+
+ mempool.space fee
+
+
+
+ {{ estimate.mempoolBaseFee | number }} sats
+
+
+
+
+
+
+ Transaction vsize fee
+
+
+
+ {{ estimate.vsizeFee | number }} sats
+
+
+
+
+
+
+
+
+ Estimated acceleration cost
+
+
+
+ {{ estimate.cost + estimate.mempoolBaseFee + estimate.vsizeFee | number }} satss
+
+
+
+
+
+
+ Cost if your tx is accelerated using {{ estimate.targetFeeRate | number : '1.0-0' }} sat/vB
+
+
+
+
+
+
+ Maximum acceleration cost
+
+
+ {{ maxCost | number }} satss
+
+
+
+
+
+
+
+ Cost if your tx is accelerated using ~{{ ((estimate.txSummary.effectiveFee + userBid) / estimate.txSummary.effectiveVsize) | number : '1.0-0' }} sat/vB
+
+
+
+
+
+
+ Available balance
+
+
+ {{ estimate.userBalance | number }} satss
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss
index e69de29bb..b6981b8a7 100644
--- a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss
+++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.scss
@@ -0,0 +1,20 @@
+.fee-card {
+ padding: 15px;
+ background-color: #1d1f31;
+}
+
+.btn-border {
+ border: solid 1px black;
+ background-color: #0c4a87;
+}
+
+.feerate.active {
+ background-color: #105fb0 !important;
+ opacity: 1;
+ border: 1px solid white !important;
+}
+
+.estimateDisabled {
+ opacity: 0.5;
+ pointer-events: none;
+}
diff --git a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts
index dc8b9b5df..bea0efb88 100644
--- a/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts
+++ b/frontend/src/app/components/accelerate-preview/accelerate-preview.component.ts
@@ -1,24 +1,169 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
+import { ApiService } from '../../services/api.service';
+import { Subscription, catchError, of, tap } from 'rxjs';
+
+export type AccelerationEstimate = {
+ txSummary: TxSummary;
+ nextBlockFee: number;
+ targetFeeRate: number;
+ userBalance: number;
+ enoughBalance: boolean;
+ cost: number;
+ mempoolBaseFee: number;
+ vsizeFee: number;
+}
+export type TxSummary = {
+ txid: string; // txid of the current transaction
+ effectiveVsize: number; // Total vsize of the dependency tree
+ effectiveFee: number; // Total fee of the dependency tree in sats
+ ancestorCount: number; // Number of ancestors
+}
+
+export const DEFAULT_BID_RATIO = 5;
+export const MIN_BID_RATIO = 2;
+export const MAX_BID_RATIO = 20;
@Component({
- selector: 'app-accelerator-preview',
+ selector: 'app-accelerate-preview',
templateUrl: 'accelerate-preview.component.html',
styleUrls: ['accelerate-preview.component.scss']
})
+export class AcceleratePreviewComponent implements OnInit, OnDestroy, OnChanges {
+ @Input() txid: string | undefined;
+ @Input() scrollEvent: boolean;
+
+ math = Math;
+ error = '';
+ showSuccess = false;
+ estimateSubscription: Subscription;
+ accelerationSubscription: Subscription;
+ estimate: any;
+ minExtraCost = 0;
+ minBidAllowed = 0;
+ maxBidAllowed = 0;
+ defaultBid = 0;
+ maxCost = 0;
+ userBid = 0;
+ selectFeeRateIndex = 2;
-export class AcceleratePreviewComponent implements OnInit {
constructor(
private apiService: ApiService
) { }
+ ngOnDestroy(): void {
+ if (this.estimateSubscription) {
+ this.estimateSubscription.unsubscribe();
+ }
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.scrollEvent) {
+ this.scrollToPreview('acceleratePreviewAnchor', 'center');
+ }
+ }
+
ngOnInit() {
- this.apiService.estimate$(this.txId).subscribe((estimate) => {
- console.log(estimate.body);
- document.getElementById('acceleratePreviewAnchor').scrollIntoView({
+ this.estimateSubscription = this.apiService.estimate$(this.txid).pipe(
+ tap((response) => {
+ if (response.status === 204) {
+ this.estimate = undefined;
+ this.error = `cannot_accelerate_tx`;
+ this.scrollToPreviewWithTimeout('mempoolError', 'center');
+ this.estimateSubscription.unsubscribe();
+ } else {
+ this.estimate = response.body;
+ if (!this.estimate) {
+ this.error = `cannot_accelerate_tx`;
+ this.scrollToPreviewWithTimeout('mempoolError', 'center');
+ this.estimateSubscription.unsubscribe();
+ }
+
+ if (this.estimate.userBalance <= 0) {
+ this.error = `not_enough_balance`;
+ this.scrollToPreviewWithTimeout('mempoolError', 'center');
+ }
+
+ // Make min extra fee at least 50% of the current tx fee
+ this.minExtraCost = Math.max(this.estimate.cost, this.estimate.txSummary.effectiveFee / 2);
+ this.minExtraCost = Math.round(this.minExtraCost);
+
+ this.minBidAllowed = this.minExtraCost * MIN_BID_RATIO;
+ this.maxBidAllowed = this.minExtraCost * MAX_BID_RATIO;
+ this.defaultBid = this.minExtraCost * DEFAULT_BID_RATIO;
+
+ this.userBid = this.defaultBid;
+ if (this.userBid < this.minBidAllowed) {
+ this.userBid = this.minBidAllowed;
+ } else if (this.userBid > this.maxBidAllowed) {
+ this.userBid = this.maxBidAllowed;
+ }
+ this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee;
+
+ if (!this.error) {
+ this.scrollToPreview('acceleratePreviewAnchor', 'center');
+ }
+ }
+ }),
+ catchError((response) => {
+ this.estimate = undefined;
+ this.error = response.error;
+ this.scrollToPreviewWithTimeout('mempoolError', 'center');
+ this.estimateSubscription.unsubscribe();
+ return of(null);
+ })
+ ).subscribe();
+ }
+
+ /**
+ * User changed his bid
+ */
+ setUserBid(multiplier: number, index: number) {
+ if (this.estimate) {
+ this.selectFeeRateIndex = index;
+ this.userBid = Math.max(0, this.minExtraCost * multiplier);
+ this.maxCost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee;
+ }
+ }
+
+ /**
+ * Scroll to element id with or without setTimeout
+ */
+ scrollToPreviewWithTimeout(id: string, position: ScrollLogicalPosition) {
+ setTimeout(() => {
+ this.scrollToPreview(id, position);
+ }, 100);
+ }
+ scrollToPreview(id: string, position: ScrollLogicalPosition) {
+ const acceleratePreviewAnchor = document.getElementById(id);
+ if (acceleratePreviewAnchor) {
+ acceleratePreviewAnchor.scrollIntoView({
behavior: 'smooth',
- inline: 'center',
- block: 'center',
+ inline: position,
+ block: position,
});
- })
+ }
+}
+
+ /**
+ * Send acceleration request
+ */
+ accelerate() {
+ if (this.accelerationSubscription) {
+ this.accelerationSubscription.unsubscribe();
+ }
+ this.accelerationSubscription = this.apiService.accelerate$(
+ this.txid,
+ this.userBid
+ ).subscribe({
+ next: () => {
+ this.showSuccess = true;
+ this.scrollToPreviewWithTimeout('successAlert', 'center');
+ this.estimateSubscription.unsubscribe();
+ },
+ error: (response) => {
+ this.error = response.error;
+ this.scrollToPreviewWithTimeout('mempoolError', 'center');
+ }
+ });
}
}
\ No newline at end of file
diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html
index 36c7ab9f3..f7dd45d3b 100644
--- a/frontend/src/app/components/transaction/transaction.component.html
+++ b/frontend/src/app/components/transaction/transaction.component.html
@@ -6,7 +6,7 @@
-
+
Accelerate this transaction using the Mempool Accelerator ™
×
@@ -78,33 +78,17 @@
+
Accelerate
-
-
-
@@ -132,10 +116,9 @@
= 7" [ngIfElse]="belowBlockLimit">
-
+
In several hours (or more)
-
- Accelerate
+ Accelerate
@@ -143,10 +126,9 @@
-
+
-
- Accelerate
+ Accelerate
diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss
index 45357471a..2e076600e 100644
--- a/frontend/src/app/components/transaction/transaction.component.scss
+++ b/frontend/src/app/components/transaction/transaction.component.scss
@@ -130,7 +130,7 @@
}
.table {
- tr td {
+ tr td {
padding: 0.75rem 0.5rem;
@media (min-width: 576px) {
padding: 0.75rem 0.75rem;
@@ -138,7 +138,7 @@
&:last-child {
text-align: right;
@media (min-width: 850px) {
- text-align: left;
+ text-align: left;
}
}
.btn {
@@ -218,25 +218,52 @@
}
}
-.eta {
- display: flex;
- justify-content: end;
- flex-wrap: wrap;
- align-content: center;
- @media (min-width: 850px) {
- justify-content: space-between;
- }
-}
-
.link.accelerator {
cursor: pointer;
}
+.eta {
+ display: flex;
+ flex-wrap: wrap;
+ align-content: center;
+ @media (min-width: 850px) {
+ justify-content: left !important;
+ }
+}
+
.accelerate {
+ display: flex !important;
align-self: auto;
margin-top: 3px;
- margin-left: 10px;
- @media (min-width: 850px) {
- justify-self: start;
+ margin-left: auto;
+ background-color: #653b9c;
+ @media (max-width: 849px) {
+ margin-left: 5px;
}
-}
\ No newline at end of file
+}
+
+.etaDeepMempool {
+ display: flex !important;
+ justify-content: end;
+ flex-wrap: wrap;
+ align-content: center;
+ @media (max-width: 995px) {
+ justify-content: left !important;
+ }
+ @media (max-width: 849px) {
+ justify-content: right !important;
+ }
+}
+
+.accelerateDeepMempool {
+ align-self: auto;
+ margin-top: 3px;
+ margin-left: auto;
+ background-color: #653b9c;
+ @media (max-width: 995px) {
+ margin-left: 0px;
+ }
+ @media (max-width: 849px) {
+ margin-left: 5px;
+ }
+}
diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts
index c3e4cc25c..ac1452835 100644
--- a/frontend/src/app/components/transaction/transaction.component.ts
+++ b/frontend/src/app/components/transaction/transaction.component.ts
@@ -83,7 +83,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
blockConversion: Price;
tooltipPosition: { x: number, y: number };
isMobile: boolean;
- acceleratorAvailable: boolean = false;
featuresEnabled: boolean;
segwitEnabled: boolean;
@@ -93,6 +92,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
accelerateCtaType: 'alert' | 'button' = 'alert';
acceleratorAvailable: boolean = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === '';
showAccelerationSummary = false;
+ scrollIntoAccelPreview = false;
@ViewChild('graphContainer')
graphContainer: ElementRef;
@@ -504,12 +504,13 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.accelerateCtaType = 'button';
}
- onAccelerateClicked(): void {
+ onAccelerateClicked() {
if (!this.txId) {
return;
}
-
this.showAccelerationSummary = true && this.acceleratorAvailable;
+ this.scrollIntoAccelPreview = !this.scrollIntoAccelPreview;
+ return false;
}
handleLoadElectrsTransactionError(error: any): Observable
{
diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts
index 2d9077a97..ea185b1ec 100644
--- a/frontend/src/app/services/api.service.ts
+++ b/frontend/src/app/services/api.service.ts
@@ -392,4 +392,8 @@ export class ApiService {
estimate$(txInput: string) {
return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' });
}
+
+ accelerate$(txInput: string, userBid: number) {
+ return this.httpClient.post(`${SERVICES_API_PREFIX}/accelerator/accelerate`, { txInput: txInput, userBid: userBid });
+ }
}
diff --git a/frontend/src/app/shared/components/mempool-error/mempool-error.component.html b/frontend/src/app/shared/components/mempool-error/mempool-error.component.html
new file mode 100644
index 000000000..020b147a9
--- /dev/null
+++ b/frontend/src/app/shared/components/mempool-error/mempool-error.component.html
@@ -0,0 +1,2 @@
+
+
diff --git a/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts b/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts
new file mode 100644
index 000000000..19e057950
--- /dev/null
+++ b/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts
@@ -0,0 +1,47 @@
+import { Component, Input, OnInit } from "@angular/core";
+import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
+
+const MempoolErrors = {
+ 'acceleration_duplicated': `This transaction has already been accelerated.`,
+ 'acceleration_outbid': `Your fee delta is too low.`,
+ 'cannot_accelerate_tx': `Cannot accelerate this transaction.`,
+ 'cannot_decode_raw_tx': `Cannot decode this raw transaction.`,
+ 'cannot_fetch_raw_tx': `Cannot find this transaction.`,
+ 'database_error': `Something went wrong. Please try again later.`,
+ 'high_sigop_tx': `This transaction cannot be accelerated.`,
+ 'invalid_acceleration_request': `This acceleration request is not valid.`,
+ 'invalid_tx_dependencies': `This transaction dependencies are not valid.`,
+ 'mempool_rejected_raw_tx': `Our mempool rejected this transaction`,
+ 'no_mining_pool_available': `No mining pool available at the moment`,
+ 'not_available': `You current subscription does not allow you to access this feature. Consider upgrading. `,
+ 'not_enough_balance': `Your account balance is too low. Please make a deposit. `,
+ 'not_verified': `You must verify your account to use this feature.`,
+ 'recommended_fees_not_available': `Recommended fees are not available right now.`,
+ 'too_many_relatives': `This transaction has too many relatives.`,
+ 'txid_not_in_mempool': `This transaction is not in the mempool.`,
+ 'waitlisted': `You are currently on the wait list. You will get notified once you are granted access.`,
+ 'not_whitelisted_by_any_pool': `You are not whitelisted by any mining pool`,
+} as { [error: string]: string };
+
+export function isMempoolError(error: string) {
+ return Object.keys(MempoolErrors).includes(error);
+}
+
+@Component({
+ selector: 'app-mempool-error',
+ templateUrl: './mempool-error.component.html'
+})
+export class MempoolErrorComponent implements OnInit {
+ @Input() error: string;
+ errorContent: SafeHtml;
+
+ constructor(private sanitizer: DomSanitizer) { }
+
+ ngOnInit(): void {
+ if (Object.keys(MempoolErrors).includes(this.error)) {
+ this.errorContent = this.sanitizer.bypassSecurityTrustHtml(MempoolErrors[this.error]);
+ } else {
+ this.errorContent = this.error;
+ }
+ }
+}
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index 891f8f987..d77eea2cf 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -93,6 +93,8 @@ import { ToggleComponent } from './components/toggle/toggle.component';
import { GeolocationComponent } from '../shared/components/geolocation/geolocation.component';
import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert.component';
import { GlobalFooterComponent } from './components/global-footer/global-footer.component';
+import { AcceleratePreviewComponent } from '../components/accelerate-preview/accelerate-preview.component';
+import { MempoolErrorComponent } from './components/mempool-error/mempool-error.component';
import { MempoolBlockOverviewComponent } from '../components/mempool-block-overview/mempool-block-overview.component';
import { ClockchainComponent } from '../components/clockchain/clockchain.component';
@@ -189,6 +191,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
GeolocationComponent,
TestnetAlertComponent,
GlobalFooterComponent,
+ AcceleratePreviewComponent,
CalculatorComponent,
BitcoinsatoshisPipe,
MempoolBlockOverviewComponent,
@@ -196,7 +199,8 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
ClockComponent,
ClockFaceComponent,
OnlyVsizeDirective,
- OnlyWeightDirective
+ OnlyWeightDirective,
+ MempoolErrorComponent,
],
imports: [
CommonModule,
@@ -310,6 +314,8 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
GeolocationComponent,
PreviewTitleComponent,
GlobalFooterComponent,
+ AcceleratePreviewComponent,
+ MempoolErrorComponent,
MempoolBlockOverviewComponent,
ClockchainComponent,