From 9b50011e75f7861ccb21f818a0ba4c5f5ab34590 Mon Sep 17 00:00:00 2001 From: malik1004x Date: Mon, 24 Aug 2026 22:24:52 +0200 Subject: [PATCH] Hide broken options in Bitcoin wallets without a private key (#3532) * hide unavailable receive page options * hide broken options in wallets without a private key * hide exporting unavailable logs * hide sign/verify on airgapped wallets * hide mweb on hwws * hide mweb ad for hww --- cw_bitcoin/lib/bitcoin_wallet.dart | 21 +++++++++++++++++++ cw_bitcoin/lib/electrum_wallet.dart | 1 + cw_core/lib/wallet_base.dart | 11 ++++++++++ .../screens/settings/other_settings_page.dart | 3 +++ lib/src/screens/settings/privacy_page.dart | 2 +- .../dashboard/dashboard_view_model.dart | 2 +- .../dashboard/receive_option_view_model.dart | 3 ++- .../settings/other_settings_view_model.dart | 6 ++++++ .../settings/privacy_settings_view_model.dart | 12 +++++++---- 9 files changed, 54 insertions(+), 7 deletions(-) diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index 4f791aeb4..ac40de051 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -7,6 +7,7 @@ import 'package:cw_bitcoin/.secrets.g.dart' as secrets; import 'package:cw_bitcoin/address_from_output.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; +import "package:cw_bitcoin/bitcoin_receive_page_option.dart"; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; @@ -33,6 +34,7 @@ import 'package:cw_core/output_info.dart'; import 'package:cw_core/payjoin_session.dart'; import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/sync_status.dart'; +import "package:cw_core/receive_page_option.dart"; import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/utils/print_verbose.dart'; @@ -417,6 +419,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { late final PayjoinManager payjoinManager; + @override + bool get hasPayjoinSupport => keys.privateKey.isNotEmpty; + + @override + bool get hasLightningSupport => lightningWallet?.sdk != null; + bool get isPayjoinAvailable => unspentCoinsInfo.values .where((element) => element.walletId == id && element.isSending && !element.isFrozen) .isNotEmpty; @@ -673,4 +681,17 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { return super.signMessage(message, address: address); } + + @override + bool receiveOptionAvailable(ReceivePageOption option) { + if(option == BitcoinReceivePageOption.lightning) { + return hasLightningSupport; + } + + if(option == BitcoinReceivePageOption.silent_payments) { + return hasSilentPaymentsScanning; + } + + return true; + } } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index c82ac8ebd..1da016931 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -407,6 +407,7 @@ abstract class ElectrumWalletBase @override bool isTestnet; + @override bool get hasSilentPaymentsScanning => type == WalletType.bitcoin && keys.privateKey.isNotEmpty; @observable diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart index 89d6356da..024095b80 100644 --- a/cw_core/lib/wallet_base.dart +++ b/cw_core/lib/wallet_base.dart @@ -1,3 +1,4 @@ +import "package:cw_core/receive_page_option.dart"; import 'package:mobx/mobx.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/transaction_info.dart'; @@ -136,4 +137,14 @@ abstract class WalletBase checkNodeHealth(); + + bool get hasPayjoinSupport => false; + bool get hasLightningSupport => false; + bool get hasSilentPaymentsScanning => false; + + // hardware wallet - bitbox, ledger, trezor. + // we also have airgap wallets but those can't sign messages + bool get canSignMessages => walletInfo.hardwareWalletType == null || walletInfo.isHardwareWallet; + + bool receiveOptionAvailable(ReceivePageOption option) => true; } diff --git a/lib/src/screens/settings/other_settings_page.dart b/lib/src/screens/settings/other_settings_page.dart index 3f5291984..512f71984 100644 --- a/lib/src/screens/settings/other_settings_page.dart +++ b/lib/src/screens/settings/other_settings_page.dart @@ -143,6 +143,7 @@ class OtherSettingsPage extends BasePage { }, }), ), + if(_otherSettingsViewModel.hasSignVerify) ListItemRegularRow( keyValue: "security_backup_page_sign_and_verify", label: S.of(context).sign_verify_title, @@ -152,10 +153,12 @@ class OtherSettingsPage extends BasePage { ], if (_otherSettingsViewModel.walletType == WalletType.bitcoin) "btc_logging": [ + if(_otherSettingsViewModel.hasLightning) ListItemRegularRow( keyValue: "export_lightning_logs", label: S.of(context).export_lightning_logs, onTap: () => onExportLNLog(context)), + if(_otherSettingsViewModel.hasPayjoin) ListItemRegularRow( keyValue: "export_payjoin_logs", label: S.of(context).export_payjoin_logs, diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 3e35f08c3..241202ff8 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -76,7 +76,7 @@ class PrivacyPage extends BasePage { }), ], "": [ - if (_privacySettingsViewModel.isBitcoin) + if (_privacySettingsViewModel.hasSilentPaymentsScanning) ListItemRegularRow( iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg", keyValue: "silent_payments", diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index fb2d53b74..e74771b1b 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -635,7 +635,7 @@ abstract class DashboardViewModelBase with Store { if (settingsStore.mwebAdDismissed) return false; - return Platform.isAndroid || Platform.isIOS; + return (Platform.isAndroid || Platform.isIOS) && !wallet.isHardwareWallet; } @action diff --git a/lib/view_model/dashboard/receive_option_view_model.dart b/lib/view_model/dashboard/receive_option_view_model.dart index 0f3afeff9..f82fd9e4c 100644 --- a/lib/view_model/dashboard/receive_option_view_model.dart +++ b/lib/view_model/dashboard/receive_option_view_model.dart @@ -35,7 +35,8 @@ abstract class ReceiveOptionViewModelBase with Store { ReceivePageOption selectedReceiveOption; @computed - List get options => _wallet.walletAddresses.receivePageOptions; + List get options => + _wallet.walletAddresses.receivePageOptions.where(_wallet.receiveOptionAvailable).toList(); String get walletTypeString => walletTypeToString(_wallet.type); diff --git a/lib/view_model/settings/other_settings_view_model.dart b/lib/view_model/settings/other_settings_view_model.dart index 36ede0802..fa3a274ae 100644 --- a/lib/view_model/settings/other_settings_view_model.dart +++ b/lib/view_model/settings/other_settings_view_model.dart @@ -47,6 +47,8 @@ abstract class OtherSettingsViewModelBase with Store { final SettingsStore _settingsStore; final SendViewModel sendViewModel; + bool get hasSignVerify => _wallet.canSignMessages; + @computed TransactionPriority get transactionPriority { final priority = _settingsStore.getPriority(walletType, chainId: chainId); @@ -173,6 +175,10 @@ abstract class OtherSettingsViewModelBase with Store { return null; } + bool get hasPayjoin => _wallet.hasPayjoinSupport; + + bool get hasLightning => _wallet.hasLightningSupport; + Future getLightningLog() async { final path = await pathForWalletDir(name: _wallet.name, type: walletType); final logFile = File("$path/lightning.log"); diff --git a/lib/view_model/settings/privacy_settings_view_model.dart b/lib/view_model/settings/privacy_settings_view_model.dart index 5c1a41225..6eeabc0a6 100644 --- a/lib/view_model/settings/privacy_settings_view_model.dart +++ b/lib/view_model/settings/privacy_settings_view_model.dart @@ -25,7 +25,12 @@ abstract class PrivacySettingsViewModelBase with Store { bool get isBitcoin => _wallet.type == WalletType.bitcoin; @computed - bool get hasMWEB => _wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid); + bool get hasSilentPaymentsScanning => _wallet.hasSilentPaymentsScanning; + + @computed + bool get hasMWEB => + _wallet.type == WalletType.litecoin && (Platform.isIOS || Platform.isAndroid) && + !_wallet.isHardwareWallet; @computed bool get isAutoGenerateSubaddressesEnabled => @@ -108,11 +113,10 @@ abstract class PrivacySettingsViewModelBase with Store { bool get usePayjoin => _settingsStore.usePayjoin; @computed - bool get canUsePayjoin => _wallet.type == WalletType.bitcoin && DeviceInfo.instance.isMobile; + bool get canUsePayjoin => _wallet.hasPayjoinSupport && DeviceInfo.instance.isMobile; @computed - bool get canUseLightning => - _wallet.type == WalletType.bitcoin && !Platform.isWindows && !Platform.isLinux; + bool get canUseLightning => _wallet.hasLightningSupport; @computed bool get useLightning => _wallet.type == WalletType.bitcoin && bitcoin!.useLightning(_wallet);