diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts
index d8cf0d73f..5053d4da3 100644
--- a/backend/src/api/common.ts
+++ b/backend/src/api/common.ts
@@ -552,6 +552,7 @@ export class Common {
value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0),
acc: tx.acceleration || undefined,
rate: tx.effectiveFeePerVsize,
+ time: tx.firstSeen || undefined,
};
}
diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts
index 687fdbef4..3af2a9967 100644
--- a/backend/src/api/mempool-blocks.ts
+++ b/backend/src/api/mempool-blocks.ts
@@ -598,7 +598,8 @@ class MempoolBlocks {
tx.value,
Math.round((tx.rate || (tx.fee / tx.vsize)) * 100) / 100,
tx.flags,
- 1
+ tx.time || 0,
+ 1,
];
} else {
return [
@@ -608,6 +609,7 @@ class MempoolBlocks {
tx.value,
Math.round((tx.rate || (tx.fee / tx.vsize)) * 100) / 100,
tx.flags,
+ tx.time || 0,
];
}
}
diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts
index 5b31f13a6..a41e3a1ba 100644
--- a/backend/src/mempool.interfaces.ts
+++ b/backend/src/mempool.interfaces.ts
@@ -200,6 +200,7 @@ export interface TransactionStripped {
value: number;
acc?: boolean;
rate?: number; // effective fee rate
+ time?: number;
}
export interface TransactionClassified extends TransactionStripped {
@@ -207,7 +208,7 @@ export interface TransactionClassified extends TransactionStripped {
}
// [txid, fee, vsize, value, rate, flags, acceleration?]
-export type TransactionCompressed = [string, number, number, number, number, number, 1?];
+export type TransactionCompressed = [string, number, number, number, number, number, number, 1?];
// [txid, rate, flags, acceleration?]
export type MempoolDeltaChange = [string, number, number, (1|0)];
diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html
index 702718742..2ef07d12c 100644
--- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html
+++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html
@@ -14,6 +14,7 @@
[blockConversion]="blockConversion"
[filterFlags]="activeFilterFlags"
[filterMode]="filterMode"
+ [relativeTime]="relativeTime"
>
diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
index f7e9d297f..f2a1f1c7c 100644
--- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
+++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
@@ -46,6 +46,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
@Input() excludeFilters: string[] = [];
@Input() filterFlags: bigint | null = null;
@Input() filterMode: FilterMode = 'and';
+ @Input() relativeTime: number | null;
@Input() blockConversion: Price;
@Input() overrideColors: ((tx: TxView) => Color) | null = null;
@Output() txClickEvent = new EventEmitter<{ tx: TransactionStripped, keyModifier: boolean}>();
diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts
index f9f6eeeb7..fec0e7090 100644
--- a/frontend/src/app/components/block-overview-graph/tx-view.ts
+++ b/frontend/src/app/components/block-overview-graph/tx-view.ts
@@ -32,6 +32,7 @@ export default class TxView implements TransactionStripped {
rate?: number;
flags: number;
bigintFlags?: bigint | null = 0b00000100_00000000_00000000_00000000n;
+ time?: number;
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf' | 'accelerated';
context?: 'projected' | 'actual';
scene?: BlockScene;
@@ -53,6 +54,7 @@ export default class TxView implements TransactionStripped {
this.scene = scene;
this.context = tx.context;
this.txid = tx.txid;
+ this.time = tx.time || 0;
this.fee = tx.fee;
this.vsize = tx.vsize;
this.value = tx.value;
diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html
index 1ef0d1686..ec60803a5 100644
--- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html
+++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html
@@ -14,6 +14,14 @@
{{ txid | shortenString : 16}}
+
+ First seen |
+ |
+
+
+ First seen |
+ |
+
Amount |
|
diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts
index f163e74fc..c6f656796 100644
--- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts
+++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts
@@ -3,6 +3,7 @@ import { Position } from '../../components/block-overview-graph/sprite-types.js'
import { Price } from '../../services/price.service';
import { TransactionStripped } from '../../interfaces/node-api.interface.js';
import { Filter, FilterMode, TransactionFlags, toFilters } from '../../shared/filters.utils';
+import { Block } from '../../interfaces/electrs.interface.js';
@Component({
selector: 'app-block-overview-tooltip',
@@ -11,6 +12,7 @@ import { Filter, FilterMode, TransactionFlags, toFilters } from '../../shared/fi
})
export class BlockOverviewTooltipComponent implements OnChanges {
@Input() tx: TransactionStripped | void;
+ @Input() relativeTime?: number;
@Input() cursorPosition: Position;
@Input() clickable: boolean;
@Input() auditEnabled: boolean = false;
@@ -19,6 +21,7 @@ export class BlockOverviewTooltipComponent implements OnChanges {
@Input() filterMode: FilterMode = 'and';
txid = '';
+ time: number = 0;
fee = 0;
value = 0;
vsize = 1;
@@ -56,6 +59,7 @@ export class BlockOverviewTooltipComponent implements OnChanges {
if (this.tx && (changes.tx || changes.filterFlags || changes.filterMode)) {
this.txid = this.tx.txid || '';
+ this.time = this.tx.time || 0;
this.fee = this.tx.fee || 0;
this.value = this.tx.value || 0;
this.vsize = this.tx.vsize || 1;
diff --git a/frontend/src/app/components/block-view/block-view.component.html b/frontend/src/app/components/block-view/block-view.component.html
index 9a2ddf373..f0dc94e2c 100644
--- a/frontend/src/app/components/block-view/block-view.component.html
+++ b/frontend/src/app/components/block-view/block-view.component.html
@@ -8,6 +8,7 @@
[orientation]="'top'"
[flip]="false"
[disableSpinner]="true"
+ [relativeTime]="block?.timestamp"
(txClickEvent)="onTxClick($event)"
>
diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html
index 0c0655c01..279830ba5 100644
--- a/frontend/src/app/components/block/block.component.html
+++ b/frontend/src/app/components/block/block.component.html
@@ -117,6 +117,7 @@
[blockConversion]="blockConversion"
[showFilters]="true"
[excludeFilters]="['replacement']"
+ [relativeTime]="block?.timestamp"
(txClickEvent)="onTxClick($event)"
>
@@ -232,7 +233,7 @@
+ [showFilters]="true" [excludeFilters]="['replacement']" [relativeTime]="block?.timestamp">
@@ -247,7 +248,7 @@
+ [showFilters]="true" [excludeFilters]="['replacement']" [relativeTime]="block?.timestamp">
diff --git a/frontend/src/app/components/eight-blocks/eight-blocks.component.html b/frontend/src/app/components/eight-blocks/eight-blocks.component.html
index 59390c953..414a693d3 100644
--- a/frontend/src/app/components/eight-blocks/eight-blocks.component.html
+++ b/frontend/src/app/components/eight-blocks/eight-blocks.component.html
@@ -12,6 +12,7 @@
[animationDuration]="animationDuration"
[animationOffset]="animationOffset"
[disableSpinner]="true"
+ [relativeTime]="blockInfo[i]?.timestamp"
(txClickEvent)="onTxClick($event)"
>
diff --git a/frontend/src/app/components/time/time.component.ts b/frontend/src/app/components/time/time.component.ts
index 679604ff5..61cc799dc 100644
--- a/frontend/src/app/components/time/time.component.ts
+++ b/frontend/src/app/components/time/time.component.ts
@@ -23,7 +23,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
@Input() time: number;
@Input() dateString: number;
- @Input() kind: 'plain' | 'since' | 'until' | 'span' = 'plain';
+ @Input() kind: 'plain' | 'since' | 'until' | 'span' | 'before' = 'plain';
@Input() fastRender = false;
@Input() fixedRender = false;
@Input() relative = false;
@@ -206,6 +206,29 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
}
}
break;
+ case 'before':
+ if (number === 1) {
+ switch (unit) { // singular (1 day)
+ case 'year': return $localize`:@@time-span:${dateStrings.i18nYear}:DATE: before`; break;
+ case 'month': return $localize`:@@time-span:${dateStrings.i18nMonth}:DATE: before`; break;
+ case 'week': return $localize`:@@time-span:${dateStrings.i18nWeek}:DATE: before`; break;
+ case 'day': return $localize`:@@time-span:${dateStrings.i18nDay}:DATE: before`; break;
+ case 'hour': return $localize`:@@time-span:${dateStrings.i18nHour}:DATE: before`; break;
+ case 'minute': return $localize`:@@time-span:${dateStrings.i18nMinute}:DATE: before`; break;
+ case 'second': return $localize`:@@time-span:${dateStrings.i18nSecond}:DATE: before`; break;
+ }
+ } else {
+ switch (unit) { // plural (2 days)
+ case 'year': return $localize`:@@time-span:${dateStrings.i18nYears}:DATE: before`; break;
+ case 'month': return $localize`:@@time-span:${dateStrings.i18nMonths}:DATE: before`; break;
+ case 'week': return $localize`:@@time-span:${dateStrings.i18nWeeks}:DATE: before`; break;
+ case 'day': return $localize`:@@time-span:${dateStrings.i18nDays}:DATE: before`; break;
+ case 'hour': return $localize`:@@time-span:${dateStrings.i18nHours}:DATE: before`; break;
+ case 'minute': return $localize`:@@time-span:${dateStrings.i18nMinutes}:DATE: before`; break;
+ case 'second': return $localize`:@@time-span:${dateStrings.i18nSeconds}:DATE: before`; break;
+ }
+ }
+ break;
default:
if (number === 1) {
switch (unit) { // singular (1 day)
diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts
index f8057fda5..9680d2069 100644
--- a/frontend/src/app/interfaces/node-api.interface.ts
+++ b/frontend/src/app/interfaces/node-api.interface.ts
@@ -230,6 +230,7 @@ export interface TransactionStripped {
rate?: number; // effective fee rate
acc?: boolean;
flags?: number | null;
+ time?: number;
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf' | 'accelerated';
context?: 'projected' | 'actual';
}
diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts
index 9553fef02..a36126051 100644
--- a/frontend/src/app/interfaces/websocket.interface.ts
+++ b/frontend/src/app/interfaces/websocket.interface.ts
@@ -100,12 +100,13 @@ export interface TransactionStripped {
acc?: boolean; // is accelerated?
rate?: number; // effective fee rate
flags?: number;
+ time?: number;
status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'censored' | 'selected' | 'rbf' | 'accelerated';
context?: 'projected' | 'actual';
}
// [txid, fee, vsize, value, rate, flags, acceleration?]
-export type TransactionCompressed = [string, number, number, number, number, number, 1?];
+export type TransactionCompressed = [string, number, number, number, number, number, number, 1?];
// [txid, rate, flags, acceleration?]
export type MempoolDeltaChange = [string, number, number, (1|0)];
diff --git a/frontend/src/app/shared/common.utils.ts b/frontend/src/app/shared/common.utils.ts
index 18a330fab..482d9567f 100644
--- a/frontend/src/app/shared/common.utils.ts
+++ b/frontend/src/app/shared/common.utils.ts
@@ -164,7 +164,8 @@ export function uncompressTx(tx: TransactionCompressed): TransactionStripped {
value: tx[3],
rate: tx[4],
flags: tx[5],
- acc: !!tx[6],
+ time: tx[6],
+ acc: !!tx[7],
};
}