- ETA
+ ETA
= 7" [ngIfElse]="belowBlockLimit">
-
+
In several hours (or more)
-
- Accelerate
+ Accelerate
@@ -110,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 5bef401d7..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,21 +218,52 @@
}
}
+.link.accelerator {
+ cursor: pointer;
+}
+
.eta {
display: flex;
- justify-content: end;
flex-wrap: wrap;
align-content: center;
@media (min-width: 850px) {
- justify-content: space-between;
+ justify-content: left !important;
}
}
.accelerate {
+ display: flex !important;
align-self: auto;
margin-top: 3px;
- @media (min-width: 850px) {
- justify-self: start;
+ margin-left: auto;
+ background-color: #653b9c;
+ @media (max-width: 849px) {
+ margin-left: 5px;
+ }
+}
+
+.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;
}
-}
\ No newline at end of file
+ @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 d12be2084..ac1452835 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';
@@ -82,13 +83,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
blockConversion: Price;
tooltipPosition: { x: number, y: number };
isMobile: boolean;
- acceleratorAvailable: boolean = false;
featuresEnabled: boolean;
segwitEnabled: boolean;
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;
+ scrollIntoAccelPreview = false;
@ViewChild('graphContainer')
graphContainer: ElementRef;
@@ -105,6 +109,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
private apiService: ApiService,
private seoService: SeoService,
private priceService: PriceService,
+ private storageService: StorageService
) {}
ngOnInit() {
@@ -112,9 +117,14 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
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;
@@ -489,6 +499,20 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.setGraphSize();
}
+ dismissAccelAlert(): void {
+ this.storageService.setValue('accel-cta-type', 'button');
+ this.accelerateCtaType = 'button';
+ }
+
+ onAccelerateClicked() {
+ if (!this.txId) {
+ return;
+ }
+ this.showAccelerationSummary = true && this.acceleratorAvailable;
+ this.scrollIntoAccelPreview = !this.scrollIntoAccelPreview;
+ return false;
+ }
+
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..ea185b1ec 100644
--- a/frontend/src/app/services/api.service.ts
+++ b/frontend/src/app/services/api.service.ts
@@ -388,4 +388,12 @@ 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' });
+ }
+
+ 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/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
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,