From 27347779fa55232f9ceea6ee4e8c7466101b85a3 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Mon, 18 Mar 2024 17:45:11 +0200 Subject: [PATCH 1/6] New versions (#1334) * Enable Exolix Improve service updates indicator New versions * Add exolix Api token to limits api * Ignore reporting network issues * Change default bitcoin node --- assets/text/Monerocom_Release_Notes.txt | 2 ++ assets/text/Release_Notes.txt | 3 +++ cw_monero/lib/monero_wallet.dart | 8 +----- lib/entities/default_settings_migration.dart | 27 +++++++++++++++++++ .../provider/exolix_exchange_provider.dart | 1 + lib/main.dart | 2 +- lib/src/widgets/services_updates_widget.dart | 13 +++++++-- lib/utils/feature_flag.dart | 2 +- scripts/android/app_env.sh | 8 +++--- scripts/ios/app_env.sh | 8 +++--- scripts/macos/app_env.sh | 8 +++--- 11 files changed, 59 insertions(+), 23 deletions(-) diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt index 05f78b809..90fcd2a75 100644 --- a/assets/text/Monerocom_Release_Notes.txt +++ b/assets/text/Monerocom_Release_Notes.txt @@ -1,2 +1,4 @@ +Monero enhancements In-App live status page for the app services +Add Exolix exchange provider Bug fixes and enhancements \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index 05f78b809..d8d4ed830 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,2 +1,5 @@ +Monero enhancements +Bitcoin support different address types (Taproot, Segwit P2WPKH/P2WSH, Legacy) In-App live status page for the app services +Add Exolix exchange provider Bug fixes and enhancements \ No newline at end of file diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index 5644f6f2e..d00a54c8f 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -574,13 +574,7 @@ abstract class MoneroWalletBase int height = 0; try { height = _getHeightByDate(walletInfo.date); - } catch (e, s) { - onError?.call(FlutterErrorDetails( - exception: e, - stack: s, - library: this.runtimeType.toString(), - )); - } + } catch (_) {} monero_wallet.setRecoveringFromSeed(isRecovery: true); monero_wallet.setRefreshFromBlockHeight(height: height); diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 0851d00f5..8ce38e4c4 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -35,6 +35,7 @@ const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002'; const nanoDefaultNodeUri = 'rpc.nano.to'; const nanoDefaultPowNodeUri = 'rpc.nano.to'; const solanaDefaultNodeUri = 'rpc.ankr.com'; +const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002'; Future defaultSettingsMigration( {required int version, @@ -201,9 +202,15 @@ Future defaultSettingsMigration( await changeSolanaCurrentNodeToDefault( sharedPreferences: sharedPreferences, nodes: nodes); break; + case 28: await _updateMoneroPriority(sharedPreferences); break; + + case 29: + await changeDefaultBitcoinNode(nodes, sharedPreferences); + break; + default: break; } @@ -702,6 +709,26 @@ Future changeDefaultMoneroNode( } } +Future changeDefaultBitcoinNode( + Box nodeSource, SharedPreferences sharedPreferences) async { + const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com'; + final currentBitcoinNodeId = + sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); + final currentBitcoinNode = + nodeSource.values.firstWhere((node) => node.key == currentBitcoinNodeId); + final needToReplaceCurrentBitcoinNode = + currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern); + + final newCakeWalletBitcoinNode = Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin); + + await nodeSource.add(newCakeWalletBitcoinNode); + + if (needToReplaceCurrentBitcoinNode) { + await sharedPreferences.setInt( + PreferencesKey.currentBitcoinElectrumSererIdKey, newCakeWalletBitcoinNode.key as int); + } +} + Future checkCurrentNodes( Box nodeSource, Box powNodeSource, SharedPreferences sharedPreferences) async { final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); diff --git a/lib/exchange/provider/exolix_exchange_provider.dart b/lib/exchange/provider/exolix_exchange_provider.dart index eb40aff73..9374439f3 100644 --- a/lib/exchange/provider/exolix_exchange_provider.dart +++ b/lib/exchange/provider/exolix_exchange_provider.dart @@ -66,6 +66,7 @@ class ExolixExchangeProvider extends ExchangeProvider { final params = { 'rateType': _getRateType(isFixedRateMode), 'amount': '1', + 'apiToken': apiKey, }; if (isFixedRateMode) { params['coinFrom'] = _normalizeCurrency(to); diff --git a/lib/main.dart b/lib/main.dart index a87bcfdad..db505f15a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -163,7 +163,7 @@ Future initializeAppConfigs() async { transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, anonpayInvoiceInfo: anonpayInvoiceInfo, - initialMigrationVersion: 28); + initialMigrationVersion: 29); } Future initialSetup( diff --git a/lib/src/widgets/services_updates_widget.dart b/lib/src/widgets/services_updates_widget.dart index 9557ff6b9..65dbe5e40 100644 --- a/lib/src/widgets/services_updates_widget.dart +++ b/lib/src/widgets/services_updates_widget.dart @@ -10,17 +10,24 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher.dart'; -class ServicesUpdatesWidget extends StatelessWidget { +class ServicesUpdatesWidget extends StatefulWidget { final Future servicesResponse; const ServicesUpdatesWidget(this.servicesResponse, {super.key}); + @override + State createState() => _ServicesUpdatesWidgetState(); +} + +class _ServicesUpdatesWidgetState extends State { + bool wasOpened = false; + @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: FutureBuilder( - future: servicesResponse, + future: widget.servicesResponse, builder: (context, state) { return InkWell( onTap: state.hasData @@ -30,6 +37,8 @@ class ServicesUpdatesWidget extends StatelessWidget { .get() .setString(PreferencesKey.serviceStatusShaKey, state.data!.currentSha); + setState(() => wasOpened = true); + showModalBottomSheet( context: context, shape: RoundedRectangleBorder( diff --git a/lib/utils/feature_flag.dart b/lib/utils/feature_flag.dart index 91a4c67ca..2a29bd949 100644 --- a/lib/utils/feature_flag.dart +++ b/lib/utils/feature_flag.dart @@ -1,5 +1,5 @@ class FeatureFlag { static const bool isCakePayEnabled = false; - static const bool isExolixEnabled = false; + static const bool isExolixEnabled = true; static const bool isInAppTorEnabled = false; } \ No newline at end of file diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index eb1aaaacc..02f874d77 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.11.1" -MONERO_COM_BUILD_NUMBER=78 +MONERO_COM_VERSION="1.12.0" +MONERO_COM_BUILD_NUMBER=79 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.14.1" -CAKEWALLET_BUILD_NUMBER=197 +CAKEWALLET_VERSION="4.15.0" +CAKEWALLET_BUILD_NUMBER=198 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index 1c778063d..b65d3e7a6 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.11.1" -MONERO_COM_BUILD_NUMBER=76 +MONERO_COM_VERSION="1.12.0" +MONERO_COM_BUILD_NUMBER=77 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.14.1" -CAKEWALLET_BUILD_NUMBER=216 +CAKEWALLET_VERSION="4.15.0" +CAKEWALLET_BUILD_NUMBER=217 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 4c84832e6..19a1e6846 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -16,13 +16,13 @@ if [ -n "$1" ]; then fi MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.1.1" -MONERO_COM_BUILD_NUMBER=9 +MONERO_COM_VERSION="1.2.0" +MONERO_COM_BUILD_NUMBER=10 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.7.1" -CAKEWALLET_BUILD_NUMBER=56 +CAKEWALLET_VERSION="1.8.0" +CAKEWALLET_BUILD_NUMBER=57 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then From 58b2dfb26cc32a1f445ad916b941fea2c910349f Mon Sep 17 00:00:00 2001 From: Serhii Date: Tue, 19 Mar 2024 21:55:34 +0200 Subject: [PATCH 2/6] Fix deep link handling issue (#1297) * Update root.dart * Revert "Update root.dart" This reverts commit 5808903aafa81c316eb8a32a462ee18392e08f2f. * Update root.dart * increase delay * fix with mobx reaction * lunchUri fix --- lib/src/screens/root/root.dart | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 5704c99ad..8a75b78bb 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/payment_request.dart'; +import 'package:cw_core/wallet_base.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; @@ -12,6 +13,7 @@ import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:mobx/mobx.dart'; import 'package:uni_links/uni_links.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart'; @@ -49,6 +51,7 @@ class RootState extends State with WidgetsBindingObserver { bool _requestAuth; StreamSubscription? stream; + ReactionDisposer? _walletReactionDisposer; Uri? launchUri; @override @@ -72,6 +75,7 @@ class RootState extends State with WidgetsBindingObserver { @override void dispose() { stream?.cancel(); + _walletReactionDisposer?.call(); super.dispose(); } @@ -169,10 +173,20 @@ class RootState extends State with WidgetsBindingObserver { ); }); } else if (_isValidPaymentUri()) { - widget.navigatorKey.currentState?.pushNamed( - Routes.send, - arguments: PaymentRequest.fromUri(launchUri), - ); + if (widget.authenticationStore.state == AuthenticationState.uninitialized) { + launchUri = null; + } else { + if (widget.appStore.wallet == null) { + waitForWalletInstance(context, launchUri!); + launchUri = null; + } else { + widget.navigatorKey.currentState?.pushNamed( + Routes.send, + arguments: PaymentRequest.fromUri(launchUri), + ); + launchUri = null; + } + } launchUri = null; } else if (isWalletConnectLink) { if (isEVMCompatibleChain(widget.appStore.wallet!.type)) { @@ -233,4 +247,24 @@ class RootState extends State with WidgetsBindingObserver { fontSize: 16.0, ); } + + void waitForWalletInstance(BuildContext context, Uri tempLaunchUri) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (context.mounted) { + _walletReactionDisposer = reaction( + (_) => widget.appStore.wallet, + (WalletBase? wallet) { + if (wallet != null) { + widget.navigatorKey.currentState?.pushNamed( + Routes.send, + arguments: PaymentRequest.fromUri(tempLaunchUri), + ); + _walletReactionDisposer?.call(); + _walletReactionDisposer = null; + } + }, + ); + } + }); + } } From a0c0ede0998124bf68b89ab95366f63613ea37d0 Mon Sep 17 00:00:00 2001 From: Serhii Date: Wed, 20 Mar 2024 00:44:00 +0200 Subject: [PATCH 3/6] Cw 588 show popup for adding to address book (#1326) * popup for adding to address book * update localization files --- lib/src/screens/send/send_page.dart | 58 ++++++++++++++----- .../contact_list/contact_view_model.dart | 4 +- lib/view_model/send/send_view_model.dart | 29 ++++++++++ res/values/strings_ar.arb | 1 + res/values/strings_bg.arb | 1 + res/values/strings_cs.arb | 1 + res/values/strings_de.arb | 3 +- res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_ha.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_id.arb | 1 + res/values/strings_it.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 3 +- res/values/strings_my.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_th.arb | 1 + res/values/strings_tl.arb | 1 + res/values/strings_tr.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_ur.arb | 1 + res/values/strings_yo.arb | 1 + res/values/strings_zh.arb | 1 + 29 files changed, 103 insertions(+), 18 deletions(-) diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index a3b7eaf85..a4c095739 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/core/auth_service.dart'; +import 'package:cake_wallet/entities/contact_record.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/template.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart'; @@ -48,6 +49,7 @@ class SendPage extends BasePage { final PaymentRequest? initialPaymentRequest; bool _effectsInstalled = false; + ContactRecord? newContactAddress; @override String get title => S.current.send; @@ -443,22 +445,50 @@ class SendPage extends BasePage { } if (state is TransactionCommitted) { - String alertContent; - if (sendViewModel.walletType == WalletType.solana) { - alertContent = - '${S.of(_dialogContext).send_success(sendViewModel.selectedCryptoCurrency.toString())}. ${S.of(_dialogContext).waitFewSecondForTxUpdate}'; + newContactAddress = + newContactAddress ?? sendViewModel.newContactAddress(); + + final successMessage = S.of(_dialogContext).send_success( + sendViewModel.selectedCryptoCurrency.toString()); + + final waitMessage = sendViewModel.walletType == WalletType.solana + ? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : ''; + + final newContactMessage = newContactAddress != null + ? '\n${S.of(context).add_contact_to_address_book}' : ''; + + final alertContent = + "$successMessage$waitMessage$newContactMessage"; + + if (newContactAddress != null) { + return AlertWithTwoActions( + alertTitle: '', + alertContent: alertContent, + rightButtonText: S.of(_dialogContext).add_contact, + leftButtonText: S.of(_dialogContext).ignor, + actionRightButton: () { + Navigator.of(_dialogContext).pop(); + RequestReviewHandler.requestReview(); + Navigator.of(context).pushNamed( + Routes.addressBookAddContact, + arguments: newContactAddress); + newContactAddress = null; + }, + actionLeftButton: () { + Navigator.of(_dialogContext).pop(); + RequestReviewHandler.requestReview(); + newContactAddress = null; + }); } else { - alertContent = S.of(_dialogContext).send_success( - sendViewModel.selectedCryptoCurrency.toString()); + return AlertWithOneAction( + alertTitle: '', + alertContent: alertContent, + buttonText: S.of(_dialogContext).ok, + buttonAction: () { + Navigator.of(_dialogContext).pop(); + RequestReviewHandler.requestReview(); + }); } - return AlertWithOneAction( - alertTitle: '', - alertContent: alertContent, - buttonText: S.of(_dialogContext).ok, - buttonAction: () { - Navigator.of(_dialogContext).pop(); - RequestReviewHandler.requestReview(); - }); } return Offstage(); diff --git a/lib/view_model/contact_list/contact_view_model.dart b/lib/view_model/contact_list/contact_view_model.dart index 258348d3d..053cfe4c5 100644 --- a/lib/view_model/contact_list/contact_view_model.dart +++ b/lib/view_model/contact_list/contact_view_model.dart @@ -48,11 +48,11 @@ abstract class ContactViewModelBase with Store { currency = null; } - Future save() async { + Future save() async { try { state = IsExecutingState(); - if (_contact != null) { + if (_contact != null && _contact!.original.isInBox) { _contact?.name = name; _contact?.address = address; _contact?.type = currency!; diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 507ed14cc..7636c485a 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; @@ -420,6 +421,34 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor } } + ContactRecord? newContactAddress () { + + final Set contactAddresses = + Set.from(contactListViewModel.contacts.map((contact) => contact.address)) + ..addAll(contactListViewModel.walletContacts.map((contact) => contact.address)); + + for (var output in outputs) { + String address; + if (output.isParsedAddress) { + address = output.parsedAddress.addresses.first; + } else { + address = output.address; + } + + if (address.isNotEmpty && !contactAddresses.contains(address)) { + + return ContactRecord( + contactListViewModel.contactSource, + Contact( + name: '', + address: address, + type: selectedCryptoCurrency, + )); + } + } + return null; + } + String translateErrorMessage( String error, WalletType walletType, diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index a5ea72ce7..900f59135 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "ﺎﻨﻫ ﺔﻄﺸﻨﻟﺍ ﺕﻻﺎﺼﺗﻻﺍ ﺮﻬﻈﺘﺳ", "add": "إضافة", "add_contact": "ﻝﺎﺼﺗﺍ ﺔﻬﺟ ﺔﻓﺎﺿﺇ", + "add_contact_to_address_book": "هل ترغب في إضافة جهة الاتصال هذه إلى دفتر العناوين الخاص بك؟", "add_custom_node": "إضافة عقدة مخصصة جديدة", "add_custom_redemption": "إضافة استرداد مخصص", "add_fund_to_card": "أضف أموالاً مدفوعة مسبقًا إلى البطاقات (حتى ${value})", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index a42460619..3e8cd148e 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Тук ще се появят активни връзки", "add": "Добави", "add_contact": "Добави контакт", + "add_contact_to_address_book": "Искате ли да добавите този контакт към вашата адресна книга?", "add_custom_node": "Добавяне на нов персонализиран Node", "add_custom_redemption": "Добавете персонализиран Redemption", "add_fund_to_card": "Добавете предплатени средства в картите (до ${value})", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 8970d394a..8a5213821 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Zde se zobrazí aktivní připojení", "add": "Přidat", "add_contact": "Přidat kontakt", + "add_contact_to_address_book": "Chcete přidat tento kontakt do svého adresáře?", "add_custom_node": "Přidat vlastní uzel", "add_custom_redemption": "Přidat vlastní uplatnění", "add_fund_to_card": "Všechny předplacené prostředky na kartě (až ${value})", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 93d421061..549f6f775 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Hier werden aktive Verbindungen angezeigt", "add": "Hinzufügen", "add_contact": "Kontakt hinzufügen", + "add_contact_to_address_book": "Möchten Sie diesen Kontakt zu Ihrem Adressbuch hinzufügen?", "add_custom_node": "Neuen benutzerdefinierten Knoten hinzufügen", "add_custom_redemption": "Benutzerdefinierte Einlösung hinzufügen", "add_fund_to_card": "Prepaid-Guthaben zu den Karten hinzufügen (bis zu ${value})", @@ -410,8 +411,8 @@ "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt", "please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist", "please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.", - "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.", "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.", + "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.", "please_select": "Bitte auswählen:", "please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.", "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 4ccade317..9b1610da5 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Active connections will appear here", "add": "Add", "add_contact": "Add contact", + "add_contact_to_address_book": "Would you like to add this contact to your address book?", "add_custom_node": "Add New Custom Node", "add_custom_redemption": "Add Custom Redemption", "add_fund_to_card": "Add prepaid funds to the cards (up to ${value})", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 611f3bd35..4847f5521 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Las conexiones activas aparecerán aquí", "add": "Añadir", "add_contact": "Agregar contacto", + "add_contact_to_address_book": "¿Le gustaría agregar este contacto a su libreta de direcciones?", "add_custom_node": "Agregar nuevo nodo personalizado", "add_custom_redemption": "Agregar redención personalizada", "add_fund_to_card": "Agregar fondos prepagos a las tarjetas (hasta ${value})", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index f00a85310..d1390a5ca 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Les connexions actives apparaîtront ici", "add": "Ajouter", "add_contact": "Ajouter le contact", + "add_contact_to_address_book": "Souhaitez-vous ajouter ce contact à votre carnet d'adresses?", "add_custom_node": "Ajouter un nouveau nœud personnalisé", "add_custom_redemption": "Ajouter un remboursement personnalisé", "add_fund_to_card": "Ajouter des fonds prépayés aux cartes (jusqu'à ${value})", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index ab314af7f..e9bd604d2 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Haɗin kai mai aiki zai bayyana a nan", "add": "Ƙara", "add_contact": "Ƙara lamba", + "add_contact_to_address_book": "Kuna so ku ƙara wannan lamba zuwa littafin adireshinku?", "add_custom_node": "Ƙara Sabon Kulli na Custom", "add_custom_redemption": "Ƙara Ceto na Musamman", "add_fund_to_card": "Ƙara kuɗin da aka riga aka biya a katunan (har zuwa ${value})", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index da7d97c46..535fd0264 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "सक्रिय कनेक्शन यहां दिखाई देंगे", "add": "जोड़ना", "add_contact": "संपर्क जोड़ें", + "add_contact_to_address_book": "क्या आप इस संपर्क को अपनी एड्रेस बुक में जोड़ना चाहेंगे?", "add_custom_node": "नया कस्टम नोड जोड़ें", "add_custom_redemption": "कस्टम रिडेम्पशन जोड़ें", "add_fund_to_card": "कार्ड में प्रीपेड धनराशि जोड़ें (${value} तक)", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 22b486a1c..9a7cab450 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Ovdje će se pojaviti aktivne veze", "add": "Dodaj", "add_contact": "Dodaj kontakt", + "add_contact_to_address_book": "Želite li dodati ovaj kontakt u svoj adresar?", "add_custom_node": "Dodaj novi prilagođeni čvor", "add_custom_redemption": "Dodaj prilagođeni otkup", "add_fund_to_card": "Dodajte unaprijed uplaćena sredstva na kartice (do ${value})", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index a2f3ed017..f29298c4f 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Koneksi aktif akan muncul di sini", "add": "Menambahkan", "add_contact": "Tambah kontak", + "add_contact_to_address_book": "Apakah Anda ingin menambahkan kontak ini ke buku alamat Anda?", "add_custom_node": "Tambahkan Node Kustom Baru", "add_custom_redemption": "Tambahkan Tukar Kustom", "add_fund_to_card": "Tambahkan dana pra-bayar ke kartu (hingga ${value})", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 015b63d47..82dd6b976 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Le connessioni attive verranno visualizzate qui", "add": "Aggiungi", "add_contact": "Aggiungi contatto", + "add_contact_to_address_book": "Vorresti aggiungere questo contatto alla tua rubrica?", "add_custom_node": "Aggiungi nuovo nodo personalizzato", "add_custom_redemption": "Aggiungi riscatto personalizzato", "add_fund_to_card": "Aggiungi fondi prepagati alle carte (fino a ${value})", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 36ec1932b..95a7643b0 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "アクティブな接続がここに表示されます", "add": "加える", "add_contact": "連絡先を追加", + "add_contact_to_address_book": "この連絡先をアドレス帳に追加しますか?", "add_custom_node": "新しいカスタム ノードを追加", "add_custom_redemption": "カスタム引き換えを追加", "add_fund_to_card": "プリペイド資金をカードに追加します(最大 ${value})", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index b51f42e8f..e8b208c28 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "활성 연결이 여기에 표시됩니다", "add": "더하다", "add_contact": "주소록에 추가", + "add_contact_to_address_book": "이 연락처를 주소록에 추가 하시겠습니까?", "add_custom_node": "새 사용자 정의 노드 추가", "add_custom_redemption": "사용자 지정 상환 추가", "add_fund_to_card": "카드에 선불 금액 추가(최대 ${value})", @@ -410,8 +411,8 @@ "placeholder_transactions": "거래가 여기에 표시됩니다", "please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.", "please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.", - "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", + "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "please_select": "선택 해주세요:", "please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.", "please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index fe719a82b..42ea07cb6 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "လက်ရှိချိတ်ဆက်မှုများ ဤနေရာတွင် ပေါ်လာပါမည်။", "add": "ထည့်ပါ။", "add_contact": "အဆက်အသွယ်ထည့်ပါ။", + "add_contact_to_address_book": "ဒီအဆက်အသွယ်ကိုမင်းရဲ့လိပ်စာစာအုပ်နဲ့ထပ်ထည့်ချင်ပါသလား။", "add_custom_node": "စိတ်ကြိုက် Node အသစ်ကို ထည့်ပါ။", "add_custom_redemption": "စိတ်ကြိုက်ရွေးယူမှုကို ထည့်ပါ။", "add_fund_to_card": "ကတ်များသို့ ကြိုတင်ငွေပေးငွေများ ထည့်ပါ (${value} အထိ)", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index ed5054abe..a00a12338 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Actieve verbindingen worden hier weergegeven", "add": "Toevoegen", "add_contact": "Contactpersoon toevoegen", + "add_contact_to_address_book": "Wilt u dit contact toevoegen aan uw adresboek?", "add_custom_node": "Voeg een nieuw aangepast knooppunt toe", "add_custom_redemption": "Voeg aangepaste inwisseling toe", "add_fund_to_card": "Voeg prepaid tegoed toe aan de kaarten (tot ${value})", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index aa567799e..1ad616bc9 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Tutaj pojawią się aktywne połączenia", "add": "Dodaj", "add_contact": "Dodaj kontakt", + "add_contact_to_address_book": "Czy chciałbyś dodać ten kontakt do swojej książki adresowej?", "add_custom_node": "Dodaj nowy węzeł niestandardowy", "add_custom_redemption": "Dodaj niestandardowe wykorzystanie", "add_fund_to_card": "Dodaj przedpłacone środki do kart (do ${value})", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index b0aa7cab5..c1b579186 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Conexões ativas aparecerão aqui", "add": "Adicionar", "add_contact": "Adicionar contato", + "add_contact_to_address_book": "Você gostaria de adicionar esse contato ao seu catálogo de endereços?", "add_custom_node": "Adicionar novo nó personalizado", "add_custom_redemption": "Adicionar resgate personalizado", "add_fund_to_card": "Adicionar fundos pré-pagos aos cartões (até ${value})", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index bfb7b62d7..f327f126a 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Здесь появятся активные подключения", "add": "Добавить", "add_contact": "Добавить контакт", + "add_contact_to_address_book": "Хотели бы вы добавить этот контакт в свою адресную книгу?", "add_custom_node": "Добавить новый пользовательский узел", "add_custom_redemption": "Добавить пользовательское погашение", "add_fund_to_card": "Добавить предоплаченные средства на карты (до ${value})", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 5da17828f..255b80df7 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "การเชื่อมต่อที่ใช้งานอยู่จะปรากฏที่นี่", "add": "เพิ่ม", "add_contact": "เพิ่มผู้ติดต่อ", + "add_contact_to_address_book": "คุณต้องการเพิ่มผู้ติดต่อนี้ในสมุดที่อยู่ของคุณหรือไม่?", "add_custom_node": "เพิ่มจุดโหนดแบบกำหนดเอง", "add_custom_redemption": "เพิ่มการรับคืนที่กำหนดเอง", "add_fund_to_card": "เพิ่มเงินสำรองไว้บนบัตร (ถึง ${value})", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index e0a0b1eae..1d7063881 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Lalabas dito ang mga aktibong koneksyon", "add": "Idagdag", "add_contact": "Magdagdag ng contact", + "add_contact_to_address_book": "Nais mo bang idagdag ang contact na ito sa iyong address book?", "add_custom_node": "Magdagdag ng bagong pasadyang node", "add_custom_redemption": "Magdagdag ng pasadyang pagtubos", "add_fund_to_card": "Magdagdag ng prepaid na pondo sa mga kard (hanggang sa ${value})", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index c4d64305e..99879d5ef 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Aktif bağlantılar burada görünecek", "add": "Ekle", "add_contact": "Kişi ekle", + "add_contact_to_address_book": "Bu kişiyi adres defterinize eklemek ister misiniz?", "add_custom_node": "Yeni Özel Düğüm Ekleme", "add_custom_redemption": "Özel Bozdurma Ekle", "add_fund_to_card": "Ön ödemeli kartlara para ekle (En fazla yüklenebilir tutar: ${value})", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 59371cdbe..63c59d475 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Тут з’являться активні підключення", "add": "Добавити", "add_contact": "Додати контакт", + "add_contact_to_address_book": "Хотіли б ви додати цей контакт до своєї адресної книги?", "add_custom_node": "Додати новий спеціальний вузол", "add_custom_redemption": "Додати спеціальне погашення", "add_fund_to_card": "Додайте передплачені кошти на картки (до ${value})", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 73b758561..08212c0b1 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "۔ﮯﮔ ﮞﻮﮨ ﺮﮨﺎﻇ ﮞﺎﮩﯾ ﺰﻨﺸﮑﻨﮐ ﻝﺎﻌﻓ", "add": "شامل کریں۔", "add_contact": "۔ﮟﯾﺮﮐ ﻞﻣﺎﺷ ﮧﻄﺑﺍﺭ", + "add_contact_to_address_book": "کیا آپ اس رابطہ کو اپنی ایڈریس بک میں شامل کرنا چاہیں گے؟", "add_custom_node": "نیا کسٹم نوڈ شامل کریں۔", "add_custom_redemption": "حسب ضرورت چھٹکارا شامل کریں۔", "add_fund_to_card": "کارڈز میں پری پیڈ فنڈز شامل کریں (${value} تک)", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 4ccf10ff6..f9b198843 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "Awọn asopọ ti nṣiṣe lọwọ yoo han nibi", "add": "Fikún", "add_contact": "Fi olubasọrọ kun", + "add_contact_to_address_book": "Ṣe o fẹ lati ṣafikun olubasọrọ yii si iwe adirẹsi rẹ?", "add_custom_node": "Fikún apẹka títun t'ẹ́ pààrọ̀", "add_custom_redemption": "Tẹ̀ iye owó t'ẹ́ fẹ́ ná", "add_fund_to_card": "Ẹ fikún owó sí àwọn káàdì (kò tóbi ju ${value})", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 3cff27996..8a61a6a4a 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -9,6 +9,7 @@ "activeConnectionsPrompt": "活动连接将出现在这里", "add": "添加", "add_contact": "增加联系人", + "add_contact_to_address_book": "您想将此联系人添加到您的通讯录中吗?", "add_custom_node": "添加新的自定义节点", "add_custom_redemption": "添加自定义兑换", "add_fund_to_card": "向卡中添加预付资金(最多 ${value})", From 5a7a0e01a735849435b56930a3efa998805db657 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Thu, 21 Mar 2024 04:51:57 +0200 Subject: [PATCH 4/6] Litcoin bitcoin cash fix (#1339) * Make address to output script a single entry point Fix network type for bitcoin cash * Add MoonPay to sell polygon * Normalize currency for moonpay widget * Minor fix * fix: litecoin & bch address types * fix: remove print * fix: network decode location * fix: missing place additional network type * fix: wrong initial address page type * fix: initial address generation * fix: btc exchange sending all, bch without change addresses * Minor fixes * Update app versions [skip ci] --------- Co-authored-by: Rafael Saes --- assets/text/Release_Notes.txt | 4 - cw_bitcoin/lib/address_to_output_script.dart | 3 + cw_bitcoin/lib/bitcoin_address_record.dart | 15 +- cw_bitcoin/lib/bitcoin_wallet.dart | 8 +- cw_bitcoin/lib/electrum_wallet.dart | 56 ++- cw_bitcoin/lib/electrum_wallet_addresses.dart | 41 +- cw_bitcoin/lib/electrum_wallet_snapshot.dart | 10 +- cw_bitcoin/lib/script_hash.dart | 7 +- cw_bitcoin/pubspec.lock | 10 +- cw_bitcoin/pubspec.yaml | 4 +- .../lib/src/bitcoin_cash_wallet.dart | 28 +- .../src/bitcoin_cash_wallet_addresses.dart | 1 + cw_bitcoin_cash/pubspec.yaml | 2 +- ios/Podfile.lock | 4 +- lib/bitcoin/cw_bitcoin.dart | 24 +- lib/buy/moonpay/moonpay_provider.dart | 10 +- lib/core/address_validator.dart | 2 +- lib/entities/provider_types.dart | 7 +- lib/src/screens/exchange/exchange_page.dart | 21 +- .../exchange/exchange_template_page.dart | 365 ++++++++---------- .../exchange/widgets/exchange_card.dart | 242 ++++++------ lib/src/screens/send/send_template_page.dart | 12 +- lib/src/screens/send/widgets/send_card.dart | 23 +- .../exchange/exchange_view_model.dart | 27 +- macos/Podfile.lock | 2 +- pubspec_base.yaml | 2 +- scripts/android/app_env.sh | 4 +- scripts/ios/app_env.sh | 4 +- scripts/macos/app_env.sh | 4 +- tool/configure.dart | 2 +- 30 files changed, 497 insertions(+), 447 deletions(-) diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index d8d4ed830..83e18c18e 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,5 +1 @@ -Monero enhancements -Bitcoin support different address types (Taproot, Segwit P2WPKH/P2WSH, Legacy) -In-App live status page for the app services -Add Exolix exchange provider Bug fixes and enhancements \ No newline at end of file diff --git a/cw_bitcoin/lib/address_to_output_script.dart b/cw_bitcoin/lib/address_to_output_script.dart index 6ae50132b..892f7a0d6 100644 --- a/cw_bitcoin/lib/address_to_output_script.dart +++ b/cw_bitcoin/lib/address_to_output_script.dart @@ -3,6 +3,9 @@ import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin; List addressToOutputScript(String address, bitcoin.BasedUtxoNetwork network) { try { + if (network == bitcoin.BitcoinCashNetwork.mainnet) { + return bitcoin.BitcoinCashAddress(address).baseAddress.toScriptPubKey().toBytes(); + } return bitcoin.addressToOutputScript(address: address, network: network); } catch (err) { print(err); diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index d8d908230..d1c3b6a61 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:bitbox/bitbox.dart' as bitbox; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/script_hash.dart' as sh; @@ -20,10 +19,9 @@ class BitcoinAddressRecord { _balance = balance, _name = name, _isUsed = isUsed, - scriptHash = - scriptHash ?? (network != null ? sh.scriptHash(address, network: network) : null); + scriptHash = scriptHash ?? sh.scriptHash(address, network: network); - factory BitcoinAddressRecord.fromJSON(String jsonSource, BasedUtxoNetwork? network) { + factory BitcoinAddressRecord.fromJSON(String jsonSource, BasedUtxoNetwork network) { final decoded = json.decode(jsonSource) as Map; return BitcoinAddressRecord( @@ -39,9 +37,7 @@ class BitcoinAddressRecord { .firstWhere((type) => type.toString() == decoded['type'] as String) : SegwitAddresType.p2wpkh, scriptHash: decoded['scriptHash'] as String?, - network: (decoded['network'] as String?) == null - ? network - : BasedUtxoNetwork.fromName(decoded['network'] as String), + network: network, ); } @@ -56,7 +52,7 @@ class BitcoinAddressRecord { String _name; bool _isUsed; String? scriptHash; - BasedUtxoNetwork? network; + BasedUtxoNetwork network; int get txCount => _txCount; @@ -76,8 +72,6 @@ class BitcoinAddressRecord { @override int get hashCode => address.hashCode; - String get cashAddr => bitbox.Address.toCashAddress(address); - BitcoinAddressType type; String updateScriptHash(BasedUtxoNetwork network) { @@ -95,6 +89,5 @@ class BitcoinAddressRecord { 'balance': balance, 'type': type.toString(), 'scriptHash': scriptHash, - 'network': network?.value, }); } diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index 3b3e9c636..bf59e8637 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -92,8 +92,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { required Box unspentCoinsInfo, required String password, }) async { - final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, - walletInfo.network != null ? BasedUtxoNetwork.fromName(walletInfo.network!) : null); + final network = walletInfo.network != null + ? BasedUtxoNetwork.fromName(walletInfo.network!) + : BitcoinNetwork.mainnet; + final snp = await ElectrumWalletSnapshot.load(name, walletInfo.type, password, network); return BitcoinWallet( mnemonic: snp.mnemonic, @@ -106,7 +108,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex, addressPageType: snp.addressPageType, - networkParam: snp.network, + networkParam: network, ); } } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index c3f40a235..86fbd6dbe 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -75,11 +75,7 @@ abstract class ElectrumWalletBase } : {}), this.unspentCoinsInfo = unspentCoinsInfo, - this.network = networkType == bitcoin.bitcoin - ? BitcoinNetwork.mainnet - : networkType == litecoinNetwork - ? LitecoinNetwork.mainnet - : BitcoinNetwork.testnet, + this.network = _getNetwork(networkType, currency), this.isTestnet = networkType == bitcoin.testnet, super(walletInfo) { this.electrumClient = electrumClient ?? ElectrumClient(); @@ -192,12 +188,13 @@ abstract class ElectrumWalletBase } } - Future _estimateTxFeeAndInputsToUse( + Future estimateTxFeeAndInputsToUse( int credentialsAmount, bool sendAll, List outputAddresses, List outputs, - BitcoinTransactionCredentials transactionCredentials, + int? feeRate, + BitcoinTransactionPriority? priority, {int? inputsCount}) async { final utxos = []; List privateKeys = []; @@ -212,7 +209,7 @@ abstract class ElectrumWalletBase allInputsAmount += utx.value; leftAmount = leftAmount - utx.value; - final address = _addressTypeFromStr(utx.address, network); + final address = addressTypeFromStr(utx.address, network); final privkey = generateECPrivate( hd: utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, index: utx.bitcoinAddressRecord.index, @@ -249,7 +246,7 @@ abstract class ElectrumWalletBase if (!sendAll) { if (changeValue > 0) { final changeAddress = await walletAddresses.getChangeAddress(); - final address = _addressTypeFromStr(changeAddress, network); + final address = addressTypeFromStr(changeAddress, network); outputAddresses.add(address); outputs.add(BitcoinOutput(address: address, value: BigInt.from(changeValue))); } @@ -258,9 +255,9 @@ abstract class ElectrumWalletBase final estimatedSize = BitcoinTransactionBuilder.estimateTransactionSize( utxos: utxos, outputs: outputs, network: network); - final fee = transactionCredentials.feeRate != null - ? feeAmountWithFeeRate(transactionCredentials.feeRate!, 0, 0, size: estimatedSize) - : feeAmountForPriority(transactionCredentials.priority!, 0, 0, size: estimatedSize); + int fee = feeRate != null + ? feeAmountWithFeeRate(feeRate, 0, 0, size: estimatedSize) + : feeAmountForPriority(priority!, 0, 0, size: estimatedSize); if (fee == 0) { throw BitcoinTransactionWrongBalanceException(currency); @@ -297,8 +294,8 @@ abstract class ElectrumWalletBase outputs.removeLast(); } - return _estimateTxFeeAndInputsToUse( - credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials, + return estimateTxFeeAndInputsToUse( + credentialsAmount, sendAll, outputAddresses, outputs, feeRate, priority, inputsCount: utxos.length + 1); } } @@ -319,7 +316,7 @@ abstract class ElectrumWalletBase for (final out in transactionCredentials.outputs) { final outputAddress = out.isParsedAddress ? out.extractedAddress! : out.address; - final address = _addressTypeFromStr(outputAddress, network); + final address = addressTypeFromStr(outputAddress, network); outputAddresses.add(address); @@ -344,8 +341,14 @@ abstract class ElectrumWalletBase } } - final estimatedTx = await _estimateTxFeeAndInputsToUse( - credentialsAmount, sendAll, outputAddresses, outputs, transactionCredentials); + final estimatedTx = await estimateTxFeeAndInputsToUse( + credentialsAmount, + sendAll, + outputAddresses, + outputs, + transactionCredentials.feeRate, + transactionCredentials.priority, + ); final txb = BitcoinTransactionBuilder( utxos: estimatedTx.utxos, @@ -391,7 +394,6 @@ abstract class ElectrumWalletBase ? SegwitAddresType.p2wpkh.toString() : walletInfo.addressPageType.toString(), 'balance': balance[currency]?.toJSON(), - 'network_type': network == BitcoinNetwork.testnet ? 'testnet' : 'mainnet', }); int feeRate(TransactionPriority priority) { @@ -852,6 +854,22 @@ abstract class ElectrumWalletBase final HD = index == null ? hd : hd.derive(index); return base64Encode(HD.signMessage(message)); } + + static BasedUtxoNetwork _getNetwork(bitcoin.NetworkType networkType, CryptoCurrency? currency) { + if (networkType == bitcoin.bitcoin && currency == CryptoCurrency.bch) { + return BitcoinCashNetwork.mainnet; + } + + if (networkType == litecoinNetwork) { + return LitecoinNetwork.mainnet; + } + + if (networkType == bitcoin.testnet) { + return BitcoinNetwork.testnet; + } + + return BitcoinNetwork.mainnet; + } } class EstimateTxParams { @@ -879,7 +897,7 @@ class EstimatedTxResult { final int amount; } -BitcoinBaseAddress _addressTypeFromStr(String address, BasedUtxoNetwork network) { +BitcoinBaseAddress addressTypeFromStr(String address, BasedUtxoNetwork network) { if (P2pkhAddress.regex.hasMatch(address)) { return P2pkhAddress.fromAddress(address: address, network: network); } else if (P2shAddress.regex.hasMatch(address)) { diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 5880f5a19..828bda8af 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -1,6 +1,5 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; -import 'package:bitbox/bitbox.dart' as bitbox; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_core/wallet_addresses.dart'; @@ -30,6 +29,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { List? initialAddresses, Map? initialRegularAddressIndex, Map? initialChangeAddressIndex, + BitcoinAddressType? initialAddressPageType, }) : _addresses = ObservableList.of((initialAddresses ?? []).toSet()), addressesByReceiveType = ObservableList.of(([]).toSet()), @@ -41,9 +41,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { .toSet()), currentReceiveAddressIndexByType = initialRegularAddressIndex ?? {}, currentChangeAddressIndexByType = initialChangeAddressIndex ?? {}, - _addressPageType = walletInfo.addressPageType != null - ? BitcoinAddressType.fromValue(walletInfo.addressPageType!) - : SegwitAddresType.p2wpkh, + _addressPageType = initialAddressPageType ?? + (walletInfo.addressPageType != null + ? BitcoinAddressType.fromValue(walletInfo.addressPageType!) + : SegwitAddresType.p2wpkh), super(walletInfo) { updateAddressesByMatch(); } @@ -52,10 +53,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { static const defaultChangeAddressesCount = 17; static const gap = 20; - static String toCashAddr(String address) => bitbox.Address.toCashAddress(address); - - static String toLegacy(String address) => bitbox.Address.toLegacyAddress(address); - final ObservableList _addresses; // Matched by addressPageType late ObservableList addressesByReceiveType; @@ -67,7 +64,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { final bitcoin.HDWallet sideHd; @observable - BitcoinAddressType _addressPageType = SegwitAddresType.p2wpkh; + late BitcoinAddressType _addressPageType; @computed BitcoinAddressType get addressPageType => _addressPageType; @@ -97,7 +94,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } } - return walletInfo.type == WalletType.bitcoinCash ? toCashAddr(receiveAddress) : receiveAddress; + return receiveAddress; } @observable @@ -105,9 +102,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @override set address(String addr) { - if (addr.startsWith('bitcoincash:')) { - addr = toLegacy(addr); - } final addressRecord = _addresses.firstWhere((addressRecord) => addressRecord.address == addr); previousAddressRecord = addressRecord; @@ -155,11 +149,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @override Future init() async { - await _generateInitialAddresses(); - await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); - await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); - await _generateInitialAddresses(type: SegwitAddresType.p2tr); - await _generateInitialAddresses(type: SegwitAddresType.p2wsh); + if (walletInfo.type == WalletType.bitcoinCash) { + await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); + } else if (walletInfo.type == WalletType.litecoin) { + await _generateInitialAddresses(); + } else if (walletInfo.type == WalletType.bitcoin) { + await _generateInitialAddresses(); + await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); + await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); + await _generateInitialAddresses(type: SegwitAddresType.p2tr); + await _generateInitialAddresses(type: SegwitAddresType.p2wsh); + } updateAddressesByMatch(); updateReceiveAddresses(); updateChangeAddresses(); @@ -229,9 +229,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { @action void updateAddress(String address, String label) { - if (address.startsWith('bitcoincash:')) { - address = toLegacy(address); - } final addressRecord = _addresses.firstWhere((addressRecord) => addressRecord.address == address); addressRecord.setNewName(label); @@ -261,7 +258,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressRecord.isHidden && !addressRecord.isUsed && // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type - addressRecord.type == SegwitAddresType.p2wpkh); + (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddresType.p2wpkh)); changeAddresses.addAll(newAddresses); } diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index 98c3753db..6f76ab312 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -17,14 +17,12 @@ class ElectrumWalletSnapshot { required this.regularAddressIndex, required this.changeAddressIndex, required this.addressPageType, - required this.network, }); final String name; final String password; final WalletType type; - final String addressPageType; - final BasedUtxoNetwork network; + final String? addressPageType; String mnemonic; List addresses; @@ -32,7 +30,8 @@ class ElectrumWalletSnapshot { Map regularAddressIndex; Map changeAddressIndex; - static Future load(String name, WalletType type, String password, BasedUtxoNetwork? network) async { + static Future load( + String name, WalletType type, String password, BasedUtxoNetwork network) async { final path = await pathForWallet(name: name, type: type); final jsonSource = await read(path: path, password: password); final data = json.decode(jsonSource) as Map; @@ -71,8 +70,7 @@ class ElectrumWalletSnapshot { balance: balance, regularAddressIndex: regularAddressIndexByType, changeAddressIndex: changeAddressIndexByType, - addressPageType: data['address_page_type'] as String? ?? SegwitAddresType.p2wpkh.toString(), - network: data['network_type'] == 'testnet' ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet, + addressPageType: data['address_page_type'] as String?, ); } } diff --git a/cw_bitcoin/lib/script_hash.dart b/cw_bitcoin/lib/script_hash.dart index 620d3d28a..2130fcbbe 100644 --- a/cw_bitcoin/lib/script_hash.dart +++ b/cw_bitcoin/lib/script_hash.dart @@ -1,8 +1,9 @@ -import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:crypto/crypto.dart'; +import 'package:cw_bitcoin/address_to_output_script.dart'; +import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin; -String scriptHash(String address, {required BasedUtxoNetwork network}) { - final outputScript = addressToOutputScript(address: address, network: network); +String scriptHash(String address, {required bitcoin.BasedUtxoNetwork network}) { + final outputScript = addressToOutputScript(address, network); final parts = sha256.convert(outputScript).toString().split(''); var res = ''; diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 25e6f269d..b39dcae07 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -79,11 +79,11 @@ packages: dependency: "direct main" description: path: "." - ref: cake-update-v1 - resolved-ref: "9611e9db77e92a8434e918cdfb620068f6fcb1aa" + ref: cake-update-v2 + resolved-ref: "3fd81d238b990bb767fc7a4fdd5053a22a142e2e" url: "https://github.com/cake-tech/bitcoin_base.git" source: git - version: "4.0.0" + version: "4.2.0" bitcoin_flutter: dependency: "direct main" description: @@ -97,10 +97,10 @@ packages: dependency: "direct main" description: name: blockchain_utils - sha256: "9701dfaa74caad4daae1785f1ec4445cf7fb94e45620bc3a4aca1b9b281dc6c9" + sha256: "38ef5f4a22441ac4370aed9071dc71c460acffc37c79b344533f67d15f24c13c" url: "https://pub.dev" source: hosted - version: "1.6.0" + version: "2.1.1" boolean_selector: dependency: transitive description: diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 847b77773..bcbb55e11 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -33,8 +33,8 @@ dependencies: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base.git - ref: cake-update-v1 - blockchain_utils: ^1.6.0 + ref: cake-update-v2 + blockchain_utils: ^2.1.1 dev_dependencies: flutter_test: diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart index 3c40cf9e9..f5835e728 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart @@ -34,7 +34,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { required WalletInfo walletInfo, required Box unspentCoinsInfo, required Uint8List seedBytes, - String? addressPageType, + BitcoinAddressType? addressPageType, List? initialAddresses, ElectrumBalance? initialBalance, Map? initialRegularAddressIndex, @@ -58,6 +58,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { mainHd: hd, sideHd: bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/1"), network: network, + initialAddressPageType: addressPageType, ); autorun((_) { this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress; @@ -84,7 +85,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { seedBytes: await Mnemonic.toSeed(mnemonic), initialRegularAddressIndex: initialRegularAddressIndex, initialChangeAddressIndex: initialChangeAddressIndex, - addressPageType: addressPageType, + addressPageType: P2pkhAddressType.p2pkh, ); } @@ -101,12 +102,31 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { password: password, walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfo, - initialAddresses: snp.addresses, + initialAddresses: snp.addresses.map((addr) { + try { + BitcoinCashAddress(addr.address); + return BitcoinAddressRecord( + addr.address, + index: addr.index, + isHidden: addr.isHidden, + type: P2pkhAddressType.p2pkh, + network: BitcoinCashNetwork.mainnet, + ); + } catch (_) { + return BitcoinAddressRecord( + AddressUtils.getCashAddrFormat(addr.address), + index: addr.index, + isHidden: addr.isHidden, + type: P2pkhAddressType.p2pkh, + network: BitcoinCashNetwork.mainnet, + ); + } + }).toList(), initialBalance: snp.balance, seedBytes: await Mnemonic.toSeed(snp.mnemonic), initialRegularAddressIndex: snp.regularAddressIndex, initialChangeAddressIndex: snp.changeAddressIndex, - addressPageType: snp.addressPageType, + addressPageType: P2pkhAddressType.p2pkh, ); } diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart index 8291ce2a5..3164651f3 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart @@ -19,6 +19,7 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi super.initialAddresses, super.initialRegularAddressIndex, super.initialChangeAddressIndex, + super.initialAddressPageType, }) : super(walletInfo); @override diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 9c098c0ff..7130b3c58 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base.git - ref: cake-update-v1 + ref: cake-update-v2 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4f3aea7ec..be72b992d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -277,7 +277,7 @@ SPEC CHECKSUMS: flutter_inappwebview_ios: 97215cf7d4677db55df76782dbd2930c5e1c1ea0 flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0 + fluttertoast: 48c57db1b71b0ce9e6bba9f31c940ff4b001293c in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d local_auth_ios: 1ba1475238daa33a6ffa2a29242558437be435ac MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb @@ -302,4 +302,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: fcb1b8418441a35b438585c9dd8374e722e6c6ca -COCOAPODS: 1.12.1 +COCOAPODS: 1.15.2 diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index b36421608..709dc9a04 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -113,13 +113,35 @@ class CWBitcoin extends Bitcoin { .map((BitcoinAddressRecord addr) => ElectrumSubAddress( id: addr.index, name: addr.name, - address: electrumWallet.type == WalletType.bitcoinCash ? addr.cashAddr : addr.address, + address: addr.address, txCount: addr.txCount, balance: addr.balance, isChange: addr.isHidden)) .toList(); } + @override + Future estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority) async { + final electrumWallet = wallet as ElectrumWallet; + final sk = ECPrivate.random(); + + final p2shAddr = sk.getPublic().toP2pkhInP2sh(); + final p2wpkhAddr = sk.getPublic().toP2wpkhAddress(); + final estimatedTx = await electrumWallet.estimateTxFeeAndInputsToUse( + 0, + true, + // Deposit address + change address + [p2shAddr, p2wpkhAddr], + [ + BitcoinOutput(address: p2shAddr, value: BigInt.zero), + BitcoinOutput(address: p2wpkhAddr, value: BigInt.zero) + ], + null, + priority as BitcoinTransactionPriority); + + return estimatedTx.amount; + } + @override String getAddress(Object wallet) { final bitcoinWallet = wallet as ElectrumWallet; diff --git a/lib/buy/moonpay/moonpay_provider.dart b/lib/buy/moonpay/moonpay_provider.dart index 0ccb73e1c..75ba45ce1 100644 --- a/lib/buy/moonpay/moonpay_provider.dart +++ b/lib/buy/moonpay/moonpay_provider.dart @@ -81,7 +81,7 @@ class MoonPaySellProvider extends BuyProvider { '', { 'apiKey': _apiKey, - 'defaultBaseCurrencyCode': currency.toString().toLowerCase(), + 'defaultBaseCurrencyCode': _normalizeCurrency(currency), 'refundWalletAddress': refundWalletAddress, }..addAll(customParams), ); @@ -134,6 +134,14 @@ class MoonPaySellProvider extends BuyProvider { ); } } + + String _normalizeCurrency(CryptoCurrency currency) { + if (currency == CryptoCurrency.maticpoly) { + return "MATIC_POLYGON"; + } + + return currency.toString().toLowerCase(); + } } class MoonPayBuyProvider extends BuyProvider { diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart index ad2c761a3..967cf9bf0 100644 --- a/lib/core/address_validator.dart +++ b/lib/core/address_validator.dart @@ -274,7 +274,7 @@ class AddressValidator extends TextValidator { '|([^0-9a-zA-Z]|^)([23][a-km-zA-HJ-NP-Z1-9]{25,34})([^0-9a-zA-Z]|\$)' //P2shAddress type '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{25,39})([^0-9a-zA-Z]|\$)' //P2wpkhAddress type '|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type - '|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)'; //P2trAddress type + '|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)'; //P2trAddress type case CryptoCurrency.ltc: return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)' '|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)' diff --git a/lib/entities/provider_types.dart b/lib/entities/provider_types.dart index f9c2f1a82..b7336c2a7 100644 --- a/lib/entities/provider_types.dart +++ b/lib/entities/provider_types.dart @@ -89,7 +89,12 @@ class ProvidersHelper { case WalletType.bitcoinCash: return [ProviderType.askEachTime, ProviderType.moonpaySell]; case WalletType.polygon: - return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.dfx]; + return [ + ProviderType.askEachTime, + ProviderType.onramper, + ProviderType.moonpaySell, + ProviderType.dfx, + ]; case WalletType.solana: return [ ProviderType.askEachTime, diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index 94b51301c..61355df05 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -384,7 +384,7 @@ class ExchangePage extends BasePage { (CryptoCurrency currency) => _onCurrencyChange(currency, exchangeViewModel, depositKey)); reaction((_) => exchangeViewModel.depositAmount, (String amount) { - if (depositKey.currentState!.amountController.text != amount) { + if (depositKey.currentState!.amountController.text != amount && amount != S.of(context).all) { depositKey.currentState!.amountController.text = amount; } }); @@ -467,7 +467,9 @@ class ExchangePage extends BasePage { .addListener(() => exchangeViewModel.depositAddress = depositAddressController.text); depositAmountController.addListener(() { - if (depositAmountController.text != exchangeViewModel.depositAmount) { + if (depositAmountController.text != exchangeViewModel.depositAmount && + depositAmountController.text != S.of(context).all) { + exchangeViewModel.isSendAllEnabled = false; _depositAmountDebounce.run(() { exchangeViewModel.changeDepositAmount(amount: depositAmountController.text); exchangeViewModel.isReceiveAmountEntered = false; @@ -589,8 +591,9 @@ class ExchangePage extends BasePage { onDispose: disposeBestRateSync, hasAllAmount: exchangeViewModel.hasAllAmount, allAmount: exchangeViewModel.hasAllAmount - ? () => exchangeViewModel.calculateDepositAllAmount() + ? () => exchangeViewModel.enableSendAllAmount() : null, + isAllAmountEnabled: exchangeViewModel.isSendAllEnabled, amountFocusNode: _depositAmountFocus, addressFocusNode: _depositAddressFocus, key: depositKey, @@ -626,8 +629,10 @@ class ExchangePage extends BasePage { }, imageArrow: arrowBottomPurple, currencyButtonColor: Colors.transparent, - addressButtonsColor: Theme.of(context).extension()!.textFieldButtonColor, - borderColor: Theme.of(context).extension()!.textFieldBorderTopPanelColor, + addressButtonsColor: + Theme.of(context).extension()!.textFieldButtonColor, + borderColor: + Theme.of(context).extension()!.textFieldBorderTopPanelColor, currencyValueValidator: (value) { return !exchangeViewModel.isFixedRateMode ? AmountValidator( @@ -673,8 +678,10 @@ class ExchangePage extends BasePage { exchangeViewModel.changeReceiveCurrency(currency: currency), imageArrow: arrowBottomCakeGreen, currencyButtonColor: Colors.transparent, - addressButtonsColor: Theme.of(context).extension()!.textFieldButtonColor, - borderColor: Theme.of(context).extension()!.textFieldBorderBottomPanelColor, + addressButtonsColor: + Theme.of(context).extension()!.textFieldButtonColor, + borderColor: + Theme.of(context).extension()!.textFieldBorderBottomPanelColor, currencyValueValidator: (value) { return exchangeViewModel.isFixedRateMode ? AmountValidator( diff --git a/lib/src/screens/exchange/exchange_template_page.dart b/lib/src/screens/exchange/exchange_template_page.dart index 3a7456dd8..d24c91dad 100644 --- a/lib/src/screens/exchange/exchange_template_page.dart +++ b/lib/src/screens/exchange/exchange_template_page.dart @@ -56,17 +56,14 @@ class ExchangeTemplatePage extends BasePage { height: 8, ); - final depositWalletName = - exchangeViewModel.depositCurrency == CryptoCurrency.xmr + final depositWalletName = exchangeViewModel.depositCurrency == CryptoCurrency.xmr ? exchangeViewModel.wallet.name : null; - final receiveWalletName = - exchangeViewModel.receiveCurrency == CryptoCurrency.xmr + final receiveWalletName = exchangeViewModel.receiveCurrency == CryptoCurrency.xmr ? exchangeViewModel.wallet.name : null; - WidgetsBinding.instance - .addPostFrameCallback((_) => _setReactions(context, exchangeViewModel)); + WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context, exchangeViewModel)); return KeyboardActions( disableScroll: true, @@ -76,128 +73,125 @@ class ExchangeTemplatePage extends BasePage { nextFocus: false, actions: [ KeyboardActionsItem( - focusNode: _depositAmountFocus, - toolbarButtons: [(_) => KeyboardDoneButton()]), + focusNode: _depositAmountFocus, toolbarButtons: [(_) => KeyboardDoneButton()]), KeyboardActionsItem( - focusNode: _receiveAmountFocus, - toolbarButtons: [(_) => KeyboardDoneButton()]) + focusNode: _receiveAmountFocus, toolbarButtons: [(_) => KeyboardDoneButton()]) ]), child: Container( - color: Theme.of(context).colorScheme.background, - child: Form( - key: _formKey, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.only(bottom: 24), - content: Container( - padding: EdgeInsets.only(bottom: 32), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24) - ), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientBottomPanelColor, - Theme.of(context).extension()!.secondGradientBottomPanelColor, - ], - stops: [0.35, 1.0], - begin: Alignment.topLeft, - end: Alignment.bottomRight), - ), - child: FocusTraversalGroup( - policy: OrderedTraversalPolicy(), - child: Column( - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24) + color: Theme.of(context).colorScheme.background, + child: Form( + key: _formKey, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 24), + content: Container( + padding: EdgeInsets.only(bottom: 32), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), + gradient: LinearGradient(colors: [ + Theme.of(context) + .extension()! + .firstGradientBottomPanelColor, + Theme.of(context) + .extension()! + .secondGradientBottomPanelColor, + ], stops: [ + 0.35, + 1.0 + ], begin: Alignment.topLeft, end: Alignment.bottomRight), + ), + child: FocusTraversalGroup( + policy: OrderedTraversalPolicy(), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24)), + gradient: LinearGradient(colors: [ + Theme.of(context) + .extension()! + .firstGradientTopPanelColor, + Theme.of(context) + .extension()! + .secondGradientTopPanelColor, + ], begin: Alignment.topLeft, end: Alignment.bottomRight), + ), + padding: EdgeInsets.fromLTRB(24, 100, 24, 32), + child: Observer( + builder: (_) => ExchangeCard( + amountFocusNode: _depositAmountFocus, + key: depositKey, + title: S.of(context).you_will_send, + initialCurrency: exchangeViewModel.depositCurrency, + initialWalletName: depositWalletName ?? '', + initialAddress: exchangeViewModel.depositCurrency == + exchangeViewModel.wallet.currency + ? exchangeViewModel.wallet.walletAddresses.address + : exchangeViewModel.depositAddress, + initialIsAmountEditable: true, + initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled, + isAmountEstimated: false, + hasRefundAddress: true, + isMoneroWallet: exchangeViewModel.isMoneroWallet, + currencies: CryptoCurrency.all, + onCurrencySelected: (currency) => + exchangeViewModel.changeDepositCurrency(currency: currency), + imageArrow: arrowBottomPurple, + currencyButtonColor: Colors.transparent, + addressButtonsColor: Theme.of(context) + .extension()! + .textFieldButtonColor, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderBottomPanelColor, + currencyValueValidator: + AmountValidator(currency: exchangeViewModel.depositCurrency), + //addressTextFieldValidator: AddressValidator( + // type: exchangeViewModel.depositCurrency), + ), + ), ), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientTopPanelColor, - Theme.of(context).extension()!.secondGradientTopPanelColor, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight), - ), - padding: EdgeInsets.fromLTRB(24, 100, 24, 32), - child: Observer( - builder: (_) => ExchangeCard( - amountFocusNode: _depositAmountFocus, - key: depositKey, - title: S.of(context).you_will_send, - initialCurrency: - exchangeViewModel.depositCurrency, - initialWalletName: depositWalletName ?? '', - initialAddress: exchangeViewModel - .depositCurrency == - exchangeViewModel.wallet.currency - ? exchangeViewModel.wallet.walletAddresses.address - : exchangeViewModel.depositAddress, - initialIsAmountEditable: true, - initialIsAddressEditable: exchangeViewModel - .isDepositAddressEnabled, - isAmountEstimated: false, - hasRefundAddress: true, - isMoneroWallet: exchangeViewModel.isMoneroWallet, - currencies: CryptoCurrency.all, - onCurrencySelected: (currency) => - exchangeViewModel.changeDepositCurrency( - currency: currency), - imageArrow: arrowBottomPurple, - currencyButtonColor: Colors.transparent, - addressButtonsColor: - Theme.of(context).extension()!.textFieldButtonColor, - borderColor: Theme.of(context).extension()!.textFieldBorderBottomPanelColor, - currencyValueValidator: AmountValidator( - currency: exchangeViewModel.depositCurrency), - //addressTextFieldValidator: AddressValidator( - // type: exchangeViewModel.depositCurrency), - ), - ), + Padding( + padding: EdgeInsets.only(top: 29, left: 24, right: 24), + child: Observer( + builder: (_) => ExchangeCard( + amountFocusNode: _receiveAmountFocus, + key: receiveKey, + title: S.of(context).you_will_get, + initialCurrency: exchangeViewModel.receiveCurrency, + initialWalletName: receiveWalletName ?? '', + initialAddress: exchangeViewModel.receiveCurrency == + exchangeViewModel.wallet.currency + ? exchangeViewModel.wallet.walletAddresses.address + : exchangeViewModel.receiveAddress, + initialIsAmountEditable: false, + isAmountEstimated: true, + isMoneroWallet: exchangeViewModel.isMoneroWallet, + currencies: exchangeViewModel.receiveCurrencies, + onCurrencySelected: (currency) => exchangeViewModel + .changeReceiveCurrency(currency: currency), + imageArrow: arrowBottomCakeGreen, + currencyButtonColor: Colors.transparent, + addressButtonsColor: Theme.of(context) + .extension()! + .textFieldButtonColor, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderBottomPanelColor, + currencyValueValidator: AmountValidator( + currency: exchangeViewModel.receiveCurrency), + //addressTextFieldValidator: AddressValidator( + // type: exchangeViewModel.receiveCurrency), + )), + ) + ], ), - Padding( - padding: EdgeInsets.only(top: 29, left: 24, right: 24), - child: Observer( - builder: (_) => ExchangeCard( - amountFocusNode: _receiveAmountFocus, - key: receiveKey, - title: S.of(context).you_will_get, - initialCurrency: - exchangeViewModel.receiveCurrency, - initialWalletName: receiveWalletName ?? '', - initialAddress: - exchangeViewModel.receiveCurrency == - exchangeViewModel.wallet.currency - ? exchangeViewModel.wallet.walletAddresses.address - : exchangeViewModel.receiveAddress, - initialIsAmountEditable: false, - isAmountEstimated: true, - isMoneroWallet: exchangeViewModel.isMoneroWallet, - currencies: exchangeViewModel.receiveCurrencies, - onCurrencySelected: (currency) => - exchangeViewModel.changeReceiveCurrency( - currency: currency), - imageArrow: arrowBottomCakeGreen, - currencyButtonColor: Colors.transparent, - addressButtonsColor: - Theme.of(context).extension()!.textFieldButtonColor, - borderColor: Theme.of(context).extension()!.textFieldBorderBottomPanelColor, - currencyValueValidator: AmountValidator( - currency: exchangeViewModel.receiveCurrency), - //addressTextFieldValidator: AddressValidator( - // type: exchangeViewModel.receiveCurrency), - )), - ) - ], + ), ), - ), - ), - bottomSectionPadding: - EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Column(children: [ + bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), + bottomSection: Column(children: [ Padding( padding: EdgeInsets.only(bottom: 15), child: Observer( @@ -217,36 +211,31 @@ class ExchangeTemplatePage extends BasePage { ), ), PrimaryButton( - onPressed: () { - if (_formKey.currentState != null && _formKey.currentState!.validate()) { - exchangeViewModel.addTemplate( - amount: exchangeViewModel.depositAmount, - depositCurrency: - exchangeViewModel.depositCurrency.name, - depositCurrencyTitle: exchangeViewModel - .depositCurrency.title + ' ${exchangeViewModel.depositCurrency.tag ?? ''}', - receiveCurrency: - exchangeViewModel.receiveCurrency.name, - receiveCurrencyTitle: exchangeViewModel - .receiveCurrency.title + ' ${exchangeViewModel.receiveCurrency.tag ?? ''}', - provider: exchangeViewModel.provider.toString(), - depositAddress: exchangeViewModel.depositAddress, - receiveAddress: exchangeViewModel.receiveAddress); - exchangeViewModel.updateTemplate(); - Navigator.of(context).pop(); - } - }, - text: S.of(context).save, - color: Theme.of(context).primaryColor, - textColor: Colors.white), - ]), - )) - ) - ); + onPressed: () { + if (_formKey.currentState != null && _formKey.currentState!.validate()) { + exchangeViewModel.addTemplate( + amount: exchangeViewModel.depositAmount, + depositCurrency: exchangeViewModel.depositCurrency.name, + depositCurrencyTitle: exchangeViewModel.depositCurrency.title + + ' ${exchangeViewModel.depositCurrency.tag ?? ''}', + receiveCurrency: exchangeViewModel.receiveCurrency.name, + receiveCurrencyTitle: exchangeViewModel.receiveCurrency.title + + ' ${exchangeViewModel.receiveCurrency.tag ?? ''}', + provider: exchangeViewModel.provider.toString(), + depositAddress: exchangeViewModel.depositAddress, + receiveAddress: exchangeViewModel.receiveAddress); + exchangeViewModel.updateTemplate(); + Navigator.of(context).pop(); + } + }, + text: S.of(context).save, + color: Theme.of(context).primaryColor, + textColor: Colors.white), + ]), + )))); } - void _setReactions( - BuildContext context, ExchangeViewModel exchangeViewModel) { + void _setReactions(BuildContext context, ExchangeViewModel exchangeViewModel) { if (_isReactionsSet) { return; } @@ -272,33 +261,27 @@ class ExchangeTemplatePage extends BasePage { // key.currentState.changeLimits(min: min, max: max); // } - _onCurrencyChange( - exchangeViewModel.receiveCurrency, exchangeViewModel, receiveKey); - _onCurrencyChange( - exchangeViewModel.depositCurrency, exchangeViewModel, depositKey); + _onCurrencyChange(exchangeViewModel.receiveCurrency, exchangeViewModel, receiveKey); + _onCurrencyChange(exchangeViewModel.depositCurrency, exchangeViewModel, depositKey); reaction( - (_) => exchangeViewModel.wallet.name, - (String _) => _onWalletNameChange( - exchangeViewModel, exchangeViewModel.receiveCurrency, receiveKey)); + (_) => exchangeViewModel.wallet.name, + (String _) => + _onWalletNameChange(exchangeViewModel, exchangeViewModel.receiveCurrency, receiveKey)); reaction( - (_) => exchangeViewModel.wallet.name, - (String _) => _onWalletNameChange( - exchangeViewModel, exchangeViewModel.depositCurrency, depositKey)); + (_) => exchangeViewModel.wallet.name, + (String _) => + _onWalletNameChange(exchangeViewModel, exchangeViewModel.depositCurrency, depositKey)); - reaction( - (_) => exchangeViewModel.receiveCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, exchangeViewModel, receiveKey)); + reaction((_) => exchangeViewModel.receiveCurrency, + (CryptoCurrency currency) => _onCurrencyChange(currency, exchangeViewModel, receiveKey)); - reaction( - (_) => exchangeViewModel.depositCurrency, - (CryptoCurrency currency) => - _onCurrencyChange(currency, exchangeViewModel, depositKey)); + reaction((_) => exchangeViewModel.depositCurrency, + (CryptoCurrency currency) => _onCurrencyChange(currency, exchangeViewModel, depositKey)); reaction((_) => exchangeViewModel.depositAmount, (String amount) { - if (depositKey.currentState!.amountController.text != amount) { + if (depositKey.currentState!.amountController.text != amount && amount != S.of(context).all) { depositKey.currentState!.amountController.text = amount; } }); @@ -309,10 +292,9 @@ class ExchangeTemplatePage extends BasePage { } }); - reaction((_) => exchangeViewModel.isDepositAddressEnabled, - (bool isEnabled) { - depositKey.currentState!.isAddressEditable(isEditable: isEnabled); - }); + reaction((_) => exchangeViewModel.isDepositAddressEnabled, (bool isEnabled) { + depositKey.currentState!.isAddressEditable(isEditable: isEnabled); + }); reaction((_) => exchangeViewModel.receiveAmount, (String amount) { if (receiveKey.currentState!.amountController.text != amount) { @@ -353,30 +335,28 @@ class ExchangeTemplatePage extends BasePage { receiveKey.currentState.changeLimits(min: null, max: null); });*/ - depositAddressController.addListener( - () => exchangeViewModel.depositAddress = depositAddressController.text); + depositAddressController + .addListener(() => exchangeViewModel.depositAddress = depositAddressController.text); depositAmountController.addListener(() { - if (depositAmountController.text != exchangeViewModel.depositAmount) { - exchangeViewModel.changeDepositAmount( - amount: depositAmountController.text); + if (depositAmountController.text != exchangeViewModel.depositAmount && + exchangeViewModel.depositAmount != S.of(context).all) { + exchangeViewModel.changeDepositAmount(amount: depositAmountController.text); exchangeViewModel.isReceiveAmountEntered = false; } }); - receiveAddressController.addListener( - () => exchangeViewModel.receiveAddress = receiveAddressController.text); + receiveAddressController + .addListener(() => exchangeViewModel.receiveAddress = receiveAddressController.text); receiveAmountController.addListener(() { if (receiveAmountController.text != exchangeViewModel.receiveAmount) { - exchangeViewModel.changeReceiveAmount( - amount: receiveAmountController.text); + exchangeViewModel.changeReceiveAmount(amount: receiveAmountController.text); exchangeViewModel.isReceiveAmountEntered = true; } }); - reaction((_) => exchangeViewModel.wallet.walletAddresses.address, - (String address) { + reaction((_) => exchangeViewModel.wallet.walletAddresses.address, (String address) { if (exchangeViewModel.depositCurrency == CryptoCurrency.xmr) { depositKey.currentState!.changeAddress(address: address); } @@ -389,29 +369,26 @@ class ExchangeTemplatePage extends BasePage { _isReactionsSet = true; } - void _onCurrencyChange(CryptoCurrency currency, - ExchangeViewModel exchangeViewModel, GlobalKey key) { + void _onCurrencyChange(CryptoCurrency currency, ExchangeViewModel exchangeViewModel, + GlobalKey key) { final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency; key.currentState!.changeSelectedCurrency(currency); - key.currentState!.changeWalletName( - isCurrentTypeWallet ? exchangeViewModel.wallet.name : ''); + key.currentState!.changeWalletName(isCurrentTypeWallet ? exchangeViewModel.wallet.name : ''); key.currentState!.changeAddress( - address: isCurrentTypeWallet - ? exchangeViewModel.wallet.walletAddresses.address : ''); + address: isCurrentTypeWallet ? exchangeViewModel.wallet.walletAddresses.address : ''); key.currentState!.changeAmount(amount: ''); } - void _onWalletNameChange(ExchangeViewModel exchangeViewModel, - CryptoCurrency currency, GlobalKey key) { + void _onWalletNameChange(ExchangeViewModel exchangeViewModel, CryptoCurrency currency, + GlobalKey key) { final isCurrentTypeWallet = currency == exchangeViewModel.wallet.currency; if (isCurrentTypeWallet) { key.currentState!.changeWalletName(exchangeViewModel.wallet.name); - key.currentState!.addressController.text = - exchangeViewModel.wallet.walletAddresses.address; + key.currentState!.addressController.text = exchangeViewModel.wallet.walletAddresses.address; } else if (key.currentState!.addressController.text == exchangeViewModel.wallet.walletAddresses.address) { key.currentState!.changeWalletName(''); diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 706ace7de..d2e3c27d4 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/core/amount_validator.dart'; import 'package:cake_wallet/entities/contact_base.dart'; import 'package:cake_wallet/themes/extensions/qr_code_theme.dart'; import 'package:cake_wallet/routes.dart'; @@ -37,6 +38,7 @@ class ExchangeCard extends StatefulWidget { this.addressButtonsColor = Colors.transparent, this.borderColor = Colors.transparent, this.hasAllAmount = false, + this.isAllAmountEnabled = false, this.amountFocusNode, this.addressFocusNode, this.allAmount, @@ -62,9 +64,11 @@ class ExchangeCard extends StatefulWidget { final Color borderColor; final FormFieldValidator? currencyValueValidator; final FormFieldValidator? addressTextFieldValidator; + final FormFieldValidator allAmountValidator = AllAmountValidator(); final FocusNode? amountFocusNode; final FocusNode? addressFocusNode; final bool hasAllAmount; + final bool isAllAmountEnabled; final VoidCallback? allAmount; final void Function(BuildContext context)? onPushPasteButton; final void Function(BuildContext context)? onPushAddressBookButton; @@ -76,15 +80,15 @@ class ExchangeCard extends StatefulWidget { class ExchangeCardState extends State { ExchangeCardState() - : _title = '', - _min = '', - _max = '', - _isAmountEditable = false, - _isAddressEditable = false, - _walletName = '', - _selectedCurrency = CryptoCurrency.btc, - _isAmountEstimated = false, - _isMoneroWallet = false; + : _title = '', + _min = '', + _max = '', + _isAmountEditable = false, + _isAddressEditable = false, + _walletName = '', + _selectedCurrency = CryptoCurrency.btc, + _isAmountEstimated = false, + _isMoneroWallet = false; final addressController = TextEditingController(); final amountController = TextEditingController(); @@ -160,6 +164,12 @@ class ExchangeCardState extends State { @override Widget build(BuildContext context) { + if (widget.isAllAmountEnabled) { + WidgetsBinding.instance.addPostFrameCallback((_) { + amountController.text = S.of(context).all; + }); + } + final copyImage = Image.asset('assets/images/copy_content.png', height: 16, width: 16, @@ -168,8 +178,7 @@ class ExchangeCardState extends State { return Container( width: double.infinity, color: Colors.transparent, - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: < - Widget>[ + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ @@ -202,40 +211,38 @@ class ExchangeCardState extends State { ), Text(_selectedCurrency.toString(), style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: Colors.white)) + fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)) ]), ), ), - _selectedCurrency.tag != null ? Padding( - padding: const EdgeInsets.only(right:3.0), - child: Container( - height: 32, - decoration: BoxDecoration( - color: widget.addressButtonsColor ?? - Theme.of(context).extension()!.textFieldButtonColor, - borderRadius: - BorderRadius.all(Radius.circular(6))), - child: Center( - child: Padding( - padding: const EdgeInsets.all(6.0), - child: Text(_selectedCurrency.tag!, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Theme.of(context).extension()!.textFieldButtonIconColor)), + if (_selectedCurrency.tag != null) + Padding( + padding: const EdgeInsets.only(right: 3.0), + child: Container( + height: 32, + decoration: BoxDecoration( + color: widget.addressButtonsColor ?? + Theme.of(context).extension()!.textFieldButtonColor, + borderRadius: BorderRadius.all(Radius.circular(6))), + child: Center( + child: Padding( + padding: const EdgeInsets.all(6.0), + child: Text(_selectedCurrency.tag!, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Theme.of(context) + .extension()! + .textFieldButtonIconColor)), + ), ), ), ), - ) : Container(), Padding( padding: const EdgeInsets.only(right: 4.0), child: Text(':', style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16, - color: Colors.white)), + fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)), ), Expanded( child: Row( @@ -249,26 +256,27 @@ class ExchangeCardState extends State { controller: amountController, enabled: _isAmountEditable, textAlign: TextAlign.left, - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: true), + keyboardType: + TextInputType.numberWithOptions(signed: false, decimal: true), inputFormatters: [ - FilteringTextInputFormatter.deny( - RegExp('[\\-|\\ ]')) + FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]')) ], hintText: '0.0000', borderColor: Colors.transparent, //widget.borderColor, textStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white), + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), placeholderTextStyle: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.hintTextColor), - validator: _isAmountEditable - ? widget.currencyValueValidator - : null), + color: Theme.of(context) + .extension()! + .hintTextColor), + validator: widget.hasAllAmount + ? widget.allAmountValidator + : _isAmountEditable + ? widget.currencyValueValidator + : null), ), ), if (widget.hasAllAmount) @@ -276,9 +284,10 @@ class ExchangeCardState extends State { height: 32, width: 32, decoration: BoxDecoration( - color: Theme.of(context).extension()!.textFieldButtonColor, - borderRadius: - BorderRadius.all(Radius.circular(6))), + color: Theme.of(context) + .extension()! + .textFieldButtonColor, + borderRadius: BorderRadius.all(Radius.circular(6))), child: InkWell( onTap: () => widget.allAmount?.call(), child: Center( @@ -287,7 +296,9 @@ class ExchangeCardState extends State { style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, - color: Theme.of(context).extension()!.textFieldButtonIconColor)), + color: Theme.of(context) + .extension()! + .textFieldButtonIconColor)), ), ), ) @@ -296,39 +307,30 @@ class ExchangeCardState extends State { ), ], )), - Divider( - height: 1, - color: Theme.of(context).extension()!.textFieldHintColor), + Divider(height: 1, color: Theme.of(context).extension()!.textFieldHintColor), Padding( padding: EdgeInsets.only(top: 5), child: Container( height: 15, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - _min != null - ? Text( - S - .of(context) - .min_value(_min ?? '', _selectedCurrency.toString()), - style: TextStyle( - fontSize: 10, - height: 1.2, - color: Theme.of(context).extension()!.hintTextColor), - ) - : Offstage(), - _min != null ? SizedBox(width: 10) : Offstage(), - _max != null - ? Text( - S - .of(context) - .max_value(_max ?? '', _selectedCurrency.toString()), - style: TextStyle( - fontSize: 10, - height: 1.2, - color: Theme.of(context).extension()!.hintTextColor)) - : Offstage(), - ])), + child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [ + _min != null + ? Text( + S.of(context).min_value(_min ?? '', _selectedCurrency.toString()), + style: TextStyle( + fontSize: 10, + height: 1.2, + color: Theme.of(context).extension()!.hintTextColor), + ) + : Offstage(), + _min != null ? SizedBox(width: 10) : Offstage(), + _max != null + ? Text(S.of(context).max_value(_max ?? '', _selectedCurrency.toString()), + style: TextStyle( + fontSize: 10, + height: 1.2, + color: Theme.of(context).extension()!.hintTextColor)) + : Offstage(), + ])), ), !_isAddressEditable && widget.hasRefundAddress ? Padding( @@ -343,7 +345,7 @@ class ExchangeCardState extends State { : Offstage(), _isAddressEditable ? FocusTraversalOrder( - order: NumericFocusOrder(2), + order: NumericFocusOrder(2), child: Padding( padding: EdgeInsets.only(top: 20), child: AddressTextField( @@ -352,27 +354,23 @@ class ExchangeCardState extends State { onURIScanned: (uri) { final paymentRequest = PaymentRequest.fromUri(uri); addressController.text = paymentRequest.address; - + if (amountController.text.isNotEmpty) { _showAmountPopup(context, paymentRequest); return; } widget.amountFocusNode?.requestFocus(); - amountController.text = paymentRequest.amount; + amountController.text = paymentRequest.amount; }, - placeholder: widget.hasRefundAddress - ? S.of(context).refund_address - : null, + placeholder: widget.hasRefundAddress ? S.of(context).refund_address : null, options: [ AddressTextFieldOption.paste, AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook, ], isBorderExist: false, - textStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white), + textStyle: + TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), hintStyle: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, @@ -381,27 +379,22 @@ class ExchangeCardState extends State { validator: widget.addressTextFieldValidator, onPushPasteButton: widget.onPushPasteButton, onPushAddressBookButton: widget.onPushAddressBookButton, - selectedCurrency: _selectedCurrency - ), - + selectedCurrency: _selectedCurrency), ), - ) + ) : Padding( padding: EdgeInsets.only(top: 10), child: Builder( builder: (context) => Stack(children: [ - FocusTraversalOrder( - order: NumericFocusOrder(3), - child: BaseTextFormField( - controller: addressController, - borderColor: Colors.transparent, - suffixIcon: - SizedBox(width: _isMoneroWallet ? 80 : 36), - textStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white), - validator: widget.addressTextFieldValidator), + FocusTraversalOrder( + order: NumericFocusOrder(3), + child: BaseTextFormField( + controller: addressController, + borderColor: Colors.transparent, + suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36), + textStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: widget.addressTextFieldValidator), ), Positioned( top: 2, @@ -421,33 +414,28 @@ class ExchangeCardState extends State { child: InkWell( onTap: () async { final contact = - await Navigator.of(context) - .pushNamed( + await Navigator.of(context).pushNamed( Routes.pickerAddressBook, arguments: widget.initialCurrency, ); - if (contact is ContactBase && - contact.address != null) { + if (contact is ContactBase) { setState(() => - addressController.text = - contact.address); - widget.onPushAddressBookButton - ?.call(context); + addressController.text = contact.address); + widget.onPushAddressBookButton?.call(context); } }, child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( - color: widget - .addressButtonsColor, + color: widget.addressButtonsColor, borderRadius: - BorderRadius.all( - Radius.circular( - 6))), + BorderRadius.all(Radius.circular(6))), child: Image.asset( 'assets/images/open_book.png', - color: Theme.of(context).extension()!.textFieldButtonIconColor, + color: Theme.of(context) + .extension()! + .textFieldButtonIconColor, )), ), )), @@ -462,18 +450,13 @@ class ExchangeCardState extends State { label: S.of(context).copy_address, child: InkWell( onTap: () { - Clipboard.setData(ClipboardData( - text: addressController - .text)); + Clipboard.setData( + ClipboardData(text: addressController.text)); showBar( - context, - S - .of(context) - .copied_to_clipboard); + context, S.of(context).copied_to_clipboard); }, child: Container( - padding: EdgeInsets.fromLTRB( - 8, 8, 0, 8), + padding: EdgeInsets.fromLTRB(8, 8, 0, 8), color: Colors.transparent, child: copyImage), ), @@ -514,7 +497,6 @@ class ExchangeCardState extends State { Navigator.of(context).pop(); }, actionLeftButton: () => Navigator.of(dialogContext).pop()); - } - ); + }); } } diff --git a/lib/src/screens/send/send_template_page.dart b/lib/src/screens/send/send_template_page.dart index 205fd62e1..52458942c 100644 --- a/lib/src/screens/send/send_template_page.dart +++ b/lib/src/screens/send/send_template_page.dart @@ -1,7 +1,5 @@ import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart'; -import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/src/widgets/trail_button.dart'; import 'package:cake_wallet/view_model/send/template_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -11,7 +9,6 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/view_model/send/send_template_view_model.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/src/screens/send/widgets/prefix_currency_icon_widget.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/src/screens/send/widgets/send_template_card.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; @@ -97,8 +94,13 @@ class SendTemplatePage extends BasePage { radius: 6.0, dotWidth: 6.0, dotHeight: 6.0, - dotColor: Theme.of(context).extension()!.indicatorDotColor, - activeDotColor: Theme.of(context).extension()!.indicatorDotTheme.activeIndicatorColor)) + dotColor: Theme.of(context) + .extension()! + .indicatorDotColor, + activeDotColor: Theme.of(context) + .extension()! + .indicatorDotTheme + .activeIndicatorColor)) : Offstage(); }, ), diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 6bd2d81e9..3f5714be9 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -80,15 +80,17 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: S.of(context).unmatched_currencies, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); + if (context.mounted) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: S.of(context).unmatched_currencies, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + } }); } } @@ -321,7 +323,8 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin calculateDepositAllAmount() async { + if (wallet.type == WalletType.litecoin || wallet.type == WalletType.bitcoinCash) { final availableBalance = wallet.balance[wallet.currency]!.available; final priority = _settingsStore.priority[wallet.type]!; final fee = wallet.calculateEstimatedFee(priority, null); @@ -545,6 +553,13 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with final amount = availableBalance - fee; changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount)); + } else if (wallet.type == WalletType.bitcoin) { + final priority = _settingsStore.priority[wallet.type]!; + + final amount = await bitcoin!.estimateFakeSendAllTxAmount( + wallet, bitcoin!.deserializeBitcoinTransactionPriority(priority.raw)); + + changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount)); } } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 106a8a652..b82513de2 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -125,4 +125,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 65ec1541137fb5b35d00490dec1bb48d4d9586bb -COCOAPODS: 1.12.1 +COCOAPODS: 1.15.2 diff --git a/pubspec_base.yaml b/pubspec_base.yaml index d4bf981cd..0293df1d1 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -110,7 +110,7 @@ dependencies: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base.git - ref: cake-update-v1 + ref: cake-update-v2 dev_dependencies: flutter_test: diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 02f874d77..ec851a89b 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -22,8 +22,8 @@ MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.0" -CAKEWALLET_BUILD_NUMBER=198 +CAKEWALLET_VERSION="4.15.1" +CAKEWALLET_BUILD_NUMBER=199 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index b65d3e7a6..53bbf4022 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -18,8 +18,8 @@ MONERO_COM_BUILD_NUMBER=77 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.0" -CAKEWALLET_BUILD_NUMBER=217 +CAKEWALLET_VERSION="4.15.1" +CAKEWALLET_BUILD_NUMBER=218 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 19a1e6846..1e8022b7b 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -21,8 +21,8 @@ MONERO_COM_BUILD_NUMBER=10 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.8.0" -CAKEWALLET_BUILD_NUMBER=57 +CAKEWALLET_VERSION="1.8.1" +CAKEWALLET_BUILD_NUMBER=58 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then diff --git a/tool/configure.dart b/tool/configure.dart index 3c1587a98..962731d06 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -70,7 +70,6 @@ import 'package:cw_core/output_info.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cake_wallet/view_model/send/output.dart'; -import 'package:cw_core/wallet_type.dart'; import 'package:hive/hive.dart'; import 'package:bitcoin_base/bitcoin_base.dart';"""; const bitcoinCWHeaders = """ @@ -127,6 +126,7 @@ abstract class Bitcoin { List getAddresses(Object wallet); String getAddress(Object wallet); + Future estimateFakeSendAllTxAmount(Object wallet, TransactionPriority priority); List getSubAddresses(Object wallet); String formatterBitcoinAmountToString({required int amount}); From ecb4f32cdaafdd0c362027f641f6b6ff0e480324 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Thu, 21 Mar 2024 15:42:16 +0200 Subject: [PATCH 5/6] Fix Exchange field not taking numbers (#1341) --- lib/src/screens/exchange/exchange_page.dart | 2 +- lib/src/screens/exchange/widgets/exchange_card.dart | 4 +--- scripts/android/app_env.sh | 4 ++-- scripts/ios/app_env.sh | 4 ++-- scripts/macos/app_env.sh | 4 ++-- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index 61355df05..1a5ab24e6 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -634,7 +634,7 @@ class ExchangePage extends BasePage { borderColor: Theme.of(context).extension()!.textFieldBorderTopPanelColor, currencyValueValidator: (value) { - return !exchangeViewModel.isFixedRateMode + return !exchangeViewModel.isFixedRateMode && value != S.of(context).all ? AmountValidator( isAutovalidate: true, currency: exchangeViewModel.depositCurrency, diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index d2e3c27d4..8fa809de9 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -272,9 +272,7 @@ class ExchangeCardState extends State { color: Theme.of(context) .extension()! .hintTextColor), - validator: widget.hasAllAmount - ? widget.allAmountValidator - : _isAmountEditable + validator: _isAmountEditable ? widget.currencyValueValidator : null), ), diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index ec851a89b..ed2b67de5 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -22,8 +22,8 @@ MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.1" -CAKEWALLET_BUILD_NUMBER=199 +CAKEWALLET_VERSION="4.15.2" +CAKEWALLET_BUILD_NUMBER=200 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index 53bbf4022..53514b39b 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -18,8 +18,8 @@ MONERO_COM_BUILD_NUMBER=77 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.15.1" -CAKEWALLET_BUILD_NUMBER=218 +CAKEWALLET_VERSION="4.15.2" +CAKEWALLET_BUILD_NUMBER=219 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 1e8022b7b..1654a022a 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -21,8 +21,8 @@ MONERO_COM_BUILD_NUMBER=10 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.8.1" -CAKEWALLET_BUILD_NUMBER=58 +CAKEWALLET_VERSION="1.8.2" +CAKEWALLET_BUILD_NUMBER=59 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then From af7fe0509969da18ae6f778210814bc020ca907e Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Thu, 21 Mar 2024 16:31:05 +0200 Subject: [PATCH 6/6] Generic fixes (#1342) * handle balance exceptions in estimating All exchange * Fix trades not showing --- cw_bitcoin/lib/electrum_wallet_addresses.dart | 4 ++- lib/bitcoin/cw_bitcoin.dart | 28 +++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 828bda8af..69d0a6385 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -220,7 +220,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { Future updateAddressesInBox() async { try { addressesMap.clear(); - addressesMap[address] = ''; + _addresses.forEach((addressRecord) { + addressesMap[addressRecord.address] = addressRecord.name; + }); await saveAddressesInBox(); } catch (e) { print(e.toString()); diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 709dc9a04..78423a8c3 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -127,19 +127,23 @@ class CWBitcoin extends Bitcoin { final p2shAddr = sk.getPublic().toP2pkhInP2sh(); final p2wpkhAddr = sk.getPublic().toP2wpkhAddress(); - final estimatedTx = await electrumWallet.estimateTxFeeAndInputsToUse( - 0, - true, - // Deposit address + change address - [p2shAddr, p2wpkhAddr], - [ - BitcoinOutput(address: p2shAddr, value: BigInt.zero), - BitcoinOutput(address: p2wpkhAddr, value: BigInt.zero) - ], - null, - priority as BitcoinTransactionPriority); + try { + final estimatedTx = await electrumWallet.estimateTxFeeAndInputsToUse( + 0, + true, + // Deposit address + change address + [p2shAddr, p2wpkhAddr], + [ + BitcoinOutput(address: p2shAddr, value: BigInt.zero), + BitcoinOutput(address: p2wpkhAddr, value: BigInt.zero) + ], + null, + priority as BitcoinTransactionPriority); - return estimatedTx.amount; + return estimatedTx.amount; + } catch (_) { + return 0; + } } @override