diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html
index 41633a0a7..542e740b7 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.html
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.html
@@ -21,6 +21,12 @@
Warning! This transaction involves deceptively similar addresses. It may be an address poisoning attack.
}
+ @if (showColdcardWarning) {
+
+ }
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.scss b/frontend/src/app/components/transactions-list/transactions-list.component.scss
index 81b097c47..004adc994 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.scss
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.scss
@@ -416,6 +416,22 @@ h2 {
}
}
+.coldcard-warning {
+ display: flex;
+ align-items: center;
+ position: relative;
+ background-color: #b71c1c;
+ border-color: #b71c1c;
+ a {
+ color: #fff;
+ }
+}
+
+.btn-close:hover,
+.btn-close:focus {
+ opacity: 1;
+}
+
@keyframes acceleratePulse {
0% { background-color: #653b9c; box-shadow: #ad7de57f 0px 0px 12px -2px; }
50% { background-color: #8457bb; box-shadow: #ad7de5 0px 0px 18px -2px;}
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts
index 45659a5b6..a83b8dc18 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -72,6 +72,7 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy {
showTaprootControlBlock: { [vinIndex: number]: boolean } = {};
showOrdData: { [key: string]: { show: boolean; inscriptions?: Inscription[]; runestone?: Runestone, runeInfo?: { [id: string]: { etching: Etching; txid: string; } }; } } = {};
similarityMatches: Map> = new Map();
+ showColdcardWarning: boolean = false;
selectedSig: { txIndex: number, vindex: number, sig: SigInfo } | null = null;
sigHighlights: { vin: boolean[], vout: boolean[] } = { vin: [], vout: [] };
@@ -186,6 +187,7 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy {
});
this.updateAddressSimilarities();
+ this.updateShowColdcardWarning();
}
refreshPrice(): void {
@@ -476,6 +478,33 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy {
}
}
+ updateShowColdcardWarning(): void {
+ const showCCWarningPref = this.storageService.getValue('showTxColdcardWarning');
+ // there's only one tx, it's the tx page, it's unconfirmed, it contains inputs that are p2sh, v0_p2wsh or p2sh-p2wsh, is multisig and network is mainnet
+ if (showCCWarningPref && showCCWarningPref === 'false') {
+ return;
+ }
+
+ if (!this.transactionPage || this.txPreview) {
+ return;
+ }
+
+ if (this.transactions.length > 1 || this.transactions[0].status.confirmed) {
+ return;
+ }
+
+ const vinPossibleCC: Vin[] = this.transactions[0].vin.filter((input: Vin) => {
+ const addressTypeInfo = new AddressTypeInfo(this.network || 'mainnet', input.prevout.scriptpubkey_address, input.prevout?.scriptpubkey_type as AddressType, [input]);
+ return ['p2sh', 'v0_p2wsh', 'p2sh-p2wsh'].includes(addressTypeInfo.type) && !!addressTypeInfo.isMultisig && addressTypeInfo.network === 'mainnet';
+ });
+
+ if (vinPossibleCC.length === 0) {
+ return;
+ }
+
+ this.showColdcardWarning = true;
+ }
+
// assume any address with 12 or more contiguous repeated substrings is fake
fakeScriptHashRegex = new RegExp(/(.+?)\1{11,}/);
isFakeScripthash(vout: Vout): boolean {
@@ -713,6 +742,12 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy {
}
}
+ dismissWarning(): void {
+ this.storageService.setValue('showTxColdcardWarning', 'false');
+ this.showColdcardWarning = false;
+ this.ref.markForCheck();
+ }
+
ngOnDestroy(): void {
this.outspendsSubscription.unsubscribe();
this.currencyChangeSubscription?.unsubscribe();