Merge remote-tracking branch 'origin/main' into CW-453-silent-payments

This commit is contained in:
Rafael Saes 2024-05-22 19:32:45 -03:00
commit dc86968022
15 changed files with 95 additions and 62 deletions

View file

@ -1,2 +1,4 @@
Bitcoin Silent Payments
Add Tron wallet
Add Tron wallet
Hardware wallets enhancements
Bug fixes

View file

@ -28,6 +28,12 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = {
description: "Standard BIP84 native segwit",
scriptType: "p2wpkh",
),
DerivationInfo(
derivationType: DerivationType.bip39,
derivationPath: "m/86'/0'/0'",
description: "Standard BIP86 Taproot",
scriptType: "p2tr",
),
DerivationInfo(
derivationType: DerivationType.bip39,
derivationPath: "m/0'",

View file

@ -14,7 +14,6 @@ import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/litecoin_network.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bip39/bip39.dart' as bip39;
part 'litecoin_wallet.g.dart';

View file

@ -377,6 +377,9 @@ class CWBitcoin extends Bitcoin {
case "p2wpkh-p2sh":
address = generateP2SHAddress(hd: hd, network: network);
break;
case "p2tr":
address = generateP2TRAddress(hd: hd, network: network);
break;
default:
continue;
}

View file

@ -281,17 +281,19 @@ class MoonPayProvider extends BuyProvider {
throw Exception('Could not launch URL');
}
} catch (e) {
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: 'MoonPay',
alertContent: 'The MoonPay service is currently unavailable: $e',
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
},
);
if (context.mounted) {
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: 'MoonPay',
alertContent: 'The MoonPay service is currently unavailable: $e',
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
},
);
}
}
}

View file

@ -313,7 +313,6 @@ Future<void> setup({
getIt.registerFactory<Box<Node>>(() => _powNodeSource, instanceName: Node.boxName + "pow");
getIt.registerSingleton(AuthenticationStore());
getIt.registerSingleton(LedgerViewModel());
getIt.registerSingleton<WalletListStore>(WalletListStore());
getIt.registerSingleton(NodeListStoreBase.instance);
getIt.registerSingleton<SettingsStore>(settingsStore);
@ -337,6 +336,8 @@ Future<void> setup({
getIt.registerSingleton<AnonpayTransactionsStore>(
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
getIt.registerLazySingleton(() => LedgerViewModel());
final secretStore = await SecretStoreBase.load(getIt.get<SecureStorage>());
getIt.registerSingleton<SecretStore>(secretStore);
@ -626,7 +627,7 @@ Future<void> setup({
getIt.get<BalanceViewModel>(),
getIt.get<ContactListViewModel>(),
_transactionDescriptionBox,
getIt.get<LedgerViewModel>(),
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null,
),
);
@ -839,10 +840,14 @@ Future<void> setup({
isSelected: isSelected));
getIt.registerFactory<RobinhoodBuyProvider>(() => RobinhoodBuyProvider(
wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
wallet: getIt.get<AppStore>().wallet!,
ledgerVM:
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
getIt.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(
wallet: getIt.get<AppStore>().wallet!, ledgerVM: getIt.get<LedgerViewModel>()));
wallet: getIt.get<AppStore>().wallet!,
ledgerVM:
getIt.get<AppStore>().wallet!.isHardwareWallet ? getIt.get<LedgerViewModel>() : null));
getIt.registerFactory<MoonPayProvider>(() => MoonPayProvider(
settingsStore: getIt.get<AppStore>().settingsStore,
@ -948,9 +953,9 @@ Future<void> setup({
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
getIt.registerFactoryParam<WalletRestoreChooseDerivationPage, List<DerivationInfo>, void>(
(credentials, _) =>
(derivations, _) =>
WalletRestoreChooseDerivationPage(getIt.get<WalletRestoreChooseDerivationViewModel>(
param1: credentials,
param1: derivations,
)));
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(

View file

@ -67,6 +67,7 @@ class PreferencesKey {
static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain';
static const lookupsOpenAlias = 'looks_up_open_alias';
static const lookupsENS = 'looks_up_ens';
static const showCameraConsent = 'show_camera_consent';
static String moneroWalletUpdateV1Key(String name) =>
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';

View file

@ -1,10 +1,14 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/permission_handler.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';
class WebViewPage extends BasePage {
WebViewPage(this._title, this._url);
@ -42,8 +46,9 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
),
initialUrlRequest: URLRequest(url: WebUri.uri(widget.uri)),
onPermissionRequest: (controller, request) async {
bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
if (!permissionGranted) {
final sharedPrefs = getIt.get<SharedPreferences>();
if (sharedPrefs.getBool(PreferencesKey.showCameraConsent) ?? true) {
final bool userConsent = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
@ -65,9 +70,12 @@ class WebViewPageBodyState extends State<WebViewPageBody> {
);
}
permissionGranted = await Permission.camera.request().isGranted;
sharedPrefs.setBool(PreferencesKey.showCameraConsent, false);
}
bool permissionGranted =
await PermissionHandler.checkPermission(Permission.camera, context);
return PermissionResponse(
resources: request.resources,
action: permissionGranted

View file

@ -3,7 +3,7 @@ import 'dart:io';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
// import 'package:cake_wallet/src/screens/connect_device/debug_device_page.dart';
import 'package:cake_wallet/src/screens/connect_device/debug_device_page.dart';
import 'package:cake_wallet/src/screens/connect_device/widgets/device_tile.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
@ -105,7 +105,7 @@ class ConnectDevicePageBodyState extends State<ConnectDevicePageBody> {
try {
_bleRefresh = ledger.scan().listen((device) => setState(() => bleDevices.add(device)))
..onError((e) {
throw e as Exception;
throw e.toString();
});
setState(() => bleIsEnabled = true);
_bleRefreshTimer?.cancel();

View file

@ -36,7 +36,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:url_launcher/url_launcher.dart';
class SendPage extends BasePage {
@ -374,17 +373,17 @@ class SendPage extends BasePage {
}
if (sendViewModel.wallet.isHardwareWallet) {
if (!sendViewModel.ledgerViewModel.isConnected) {
if (!sendViewModel.ledgerViewModel!.isConnected) {
await Navigator.of(context).pushNamed(Routes.connectDevices,
arguments: ConnectDevicePageParams(
walletType: sendViewModel.walletType,
onConnectDevice: (BuildContext context, _) {
sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
Navigator.of(context).pop();
},
));
} else {
sendViewModel.ledgerViewModel.setLedger(sendViewModel.wallet);
sendViewModel.ledgerViewModel!.setLedger(sendViewModel.wallet);
}
}

View file

@ -363,6 +363,8 @@ abstract class DashboardViewModelBase with Store {
.toList();
}
bool get hasBuyProviders => ProvidersHelper.getAvailableBuyProviderTypes(wallet.type).isNotEmpty;
List<BuyProvider> get availableSellProviders {
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes(wallet.type);
return providerTypes
@ -372,6 +374,8 @@ abstract class DashboardViewModelBase with Store {
.toList();
}
bool get hasSellProviders => ProvidersHelper.getAvailableSellProviderTypes(wallet.type).isNotEmpty;
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
@action
@ -384,13 +388,13 @@ abstract class DashboardViewModelBase with Store {
bool hasExchangeAction;
@computed
bool get isEnabledBuyAction => !settingsStore.disableBuy && availableBuyProviders.isNotEmpty;
bool get isEnabledBuyAction => !settingsStore.disableBuy && hasBuyProviders;
@observable
bool hasBuyAction;
@computed
bool get isEnabledSellAction => !settingsStore.disableSell && availableSellProviders.isNotEmpty;
bool get isEnabledSellAction => !settingsStore.disableSell && hasSellProviders;
@observable
bool hasSellAction;
@ -529,34 +533,38 @@ abstract class DashboardViewModelBase with Store {
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
Future<List<String>> checkAffectedWallets() async {
// await load file
final vulnerableSeedsString = await rootBundle
.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
final vulnerableSeeds = vulnerableSeedsString.split("\n");
try {
// await load file
final vulnerableSeedsString = await rootBundle
.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
final vulnerableSeeds = vulnerableSeedsString.split("\n");
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
List<String> affectedWallets = [];
for (var walletInfo in walletInfoSource.values) {
if (walletInfo.type == WalletType.bitcoin) {
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?;
List<String> affectedWallets = [];
for (var walletInfo in walletInfoSource.values) {
if (walletInfo.type == WalletType.bitcoin) {
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?;
if (mnemonic == null) continue;
if (mnemonic == null) continue;
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
final seedSha = bytesToHex(hash.bytes);
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
final seedSha = bytesToHex(hash.bytes);
if (vulnerableSeeds.contains(seedSha)) {
affectedWallets.add(walletInfo.name);
if (vulnerableSeeds.contains(seedSha)) {
affectedWallets.add(walletInfo.name);
}
}
}
}
return affectedWallets;
return affectedWallets;
} catch (_) {
return [];
}
}
Future<ServicesResponse> getServicesStatus() async {

View file

@ -272,7 +272,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
final SendTemplateViewModel sendTemplateViewModel;
final BalanceViewModel balanceViewModel;
final ContactListViewModel contactListViewModel;
final LedgerViewModel ledgerViewModel;
final LedgerViewModel? ledgerViewModel;
final FiatConversionStore _fiatConversationStore;
final Box<TransactionDescription> transactionDescriptionBox;
@ -368,7 +368,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
final errorCode = e.errorCode.toRadixString(16);
final fallbackMsg =
e.message.isNotEmpty ? e.message : "Unexpected Ledger Error Code: $errorCode";
final errorMsg = ledgerViewModel.interpretErrorCode(errorCode) ?? fallbackMsg;
final errorMsg = ledgerViewModel!.interpretErrorCode(errorCode) ?? fallbackMsg;
state = FailureState(errorMsg);
} else {

View file

@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.13.2"
MONERO_COM_BUILD_NUMBER=88
MONERO_COM_VERSION="1.14.0"
MONERO_COM_BUILD_NUMBER=89
MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app"
MONERO_COM_SCHEME="monero.com"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.17.0"
CAKEWALLET_BUILD_NUMBER=213
CAKEWALLET_BUILD_NUMBER=215
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
CAKEWALLET_SCHEME="cakewallet"
@ -72,4 +72,4 @@ export APP_ANDROID_VERSION
export APP_ANDROID_BUILD_NUMBER
export APP_ANDROID_BUNDLE_ID
export APP_ANDROID_PACKAGE
export APP_ANDROID_SCHEME
export APP_ANDROID_SCHEME

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.13.2"
MONERO_COM_BUILD_NUMBER=86
MONERO_COM_VERSION="1.14.0"
MONERO_COM_BUILD_NUMBER=87
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.17.0"
CAKEWALLET_BUILD_NUMBER=241
CAKEWALLET_BUILD_NUMBER=244
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven"

View file

@ -16,13 +16,13 @@ if [ -n "$1" ]; then
fi
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.3.2"
MONERO_COM_BUILD_NUMBER=19
MONERO_COM_VERSION="1.4.0"
MONERO_COM_BUILD_NUMBER=20
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.10.0"
CAKEWALLET_BUILD_NUMBER=75
CAKEWALLET_BUILD_NUMBER=76
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then