From fb3f64facfb2dd5b6eb1b236a8c1fc074384f3ab Mon Sep 17 00:00:00 2001 From: David Adegoke <64401859+Blazebrain@users.noreply.github.com> Date: Fri, 16 Aug 2024 23:21:03 +0100 Subject: [PATCH 01/10] fix: Restore backup bug fix and clean up sol error message (#1614) * fix: Restore backup bug fix and clean up sol error message * fix: Add async await to reinitialize --- lib/reactions/bootstrap.dart | 10 ++++---- .../on_authentication_state_change.dart | 16 +++++++++++-- lib/view_model/send/send_view_model.dart | 24 +++++++++++++++++++ res/values/strings_ar.arb | 2 ++ res/values/strings_bg.arb | 2 ++ res/values/strings_cs.arb | 2 ++ res/values/strings_de.arb | 2 ++ res/values/strings_en.arb | 2 ++ res/values/strings_es.arb | 2 ++ res/values/strings_fr.arb | 2 ++ res/values/strings_ha.arb | 2 ++ res/values/strings_hi.arb | 2 ++ res/values/strings_hr.arb | 2 ++ res/values/strings_id.arb | 2 ++ res/values/strings_it.arb | 2 ++ res/values/strings_ja.arb | 2 ++ res/values/strings_ko.arb | 2 ++ res/values/strings_my.arb | 2 ++ res/values/strings_nl.arb | 2 ++ res/values/strings_pl.arb | 2 ++ res/values/strings_pt.arb | 2 ++ res/values/strings_ru.arb | 2 ++ res/values/strings_th.arb | 2 ++ res/values/strings_tl.arb | 4 +++- res/values/strings_tr.arb | 2 ++ res/values/strings_uk.arb | 2 ++ res/values/strings_ur.arb | 2 ++ res/values/strings_yo.arb | 2 ++ res/values/strings_zh.arb | 2 ++ 29 files changed, 95 insertions(+), 9 deletions(-) diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index e78d8a01d..5b1a0ace7 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -21,16 +21,14 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async { final settingsStore = getIt.get<SettingsStore>(); final fiatConversionStore = getIt.get<FiatConversionStore>(); - final currentWalletName = getIt - .get<SharedPreferences>() - .getString(PreferencesKey.currentWalletName); + final currentWalletName = + getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName); if (currentWalletName != null) { authenticationStore.installed(); } - startAuthenticationStateChange(authenticationStore, navigatorKey); - startCurrentWalletChangeReaction( - appStore, settingsStore, fiatConversionStore); + await startAuthenticationStateChange(authenticationStore, navigatorKey); + startCurrentWalletChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore); startOnCurrentNodeChangeReaction(appStore); diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index 95cbd51df..014306b98 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -13,8 +13,20 @@ ReactionDisposer? _onAuthenticationStateChange; dynamic loginError; StreamController<dynamic> authenticatedErrorStreamController = StreamController<dynamic>(); -void startAuthenticationStateChange( - AuthenticationStore authenticationStore, GlobalKey<NavigatorState> navigatorKey) { +Future<void> reInitializeStreamController() async { + if (!authenticatedErrorStreamController.isClosed) { + await authenticatedErrorStreamController.close(); + } + + authenticatedErrorStreamController = StreamController<dynamic>(); +} + +Future<void> startAuthenticationStateChange( + AuthenticationStore authenticationStore, + GlobalKey<NavigatorState> navigatorKey, +) async { + await reInitializeStreamController(); + authenticatedErrorStreamController.stream.listen((event) { if (authenticationStore.state == AuthenticationState.allowed) { ExceptionHandler.showError(event.toString(), delayInSeconds: 3); diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index d0514bb19..863c83957 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -583,6 +583,30 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor String errorMessage = error.toString(); if (walletType == WalletType.solana) { + if (errorMessage.contains('insufficient lamports')) { + double solValueNeeded = 0.0; + + // Regular expression to match the number after "need". This shows the exact lamports the user needs to perform the transaction. + RegExp regExp = RegExp(r'need (\d+)'); + + // Find the match + Match? match = regExp.firstMatch(errorMessage); + + if (match != null) { + String neededAmount = match.group(1)!; + final lamportsNeeded = int.tryParse(neededAmount); + + // 5000 lamport used here is the constant for sending a transaction on solana + int lamportsPerSol = 1000000000; + + solValueNeeded = + lamportsNeeded != null ? ((lamportsNeeded + 5000) / lamportsPerSol) : 0.0; + return S.current.insufficient_lamports(solValueNeeded.toString()); + } else { + print("No match found."); + return S.current.insufficient_lamport_for_tx; + } + } if (errorMessage.contains('insufficient funds for rent')) { return S.current.insufficientFundsForRentError; } diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 98cafdebc..a73067383 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -338,6 +338,8 @@ "incoming": "الواردة", "incorrect_seed": "النص الذي تم إدخاله غير صالح.", "inputs": "المدخلات", + "insufficient_lamport_for_tx": "ليس لديك ما يكفي من SOL لتغطية المعاملة ورسوم المعاملات الخاصة بها. يرجى إضافة المزيد من SOL إلى محفظتك أو تقليل كمية SOL التي ترسلها.", + "insufficient_lamports": "ليس لديك ما يكفي من SOL لتغطية المعاملة ورسوم المعاملات الخاصة بها. تحتاج على الأقل ${solValueNeeded} sol. يرجى إضافة المزيد من sol إلى محفظتك أو تقليل مبلغ sol الذي ترسله", "insufficientFundsForRentError": "ليس لديك ما يكفي من SOL لتغطية رسوم المعاملة والإيجار للحساب. يرجى إضافة المزيد من sol إلى محفظتك أو تقليل مبلغ sol الذي ترسله", "introducing_cake_pay": "نقدم لكم Cake Pay!", "invalid_input": "مدخل غير صالح", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index b51167dab..b60cbc55c 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -338,6 +338,8 @@ "incoming": "Входящи", "incorrect_seed": "Въведеният текст е невалиден.", "inputs": "Входове", + "insufficient_lamport_for_tx": "Нямате достатъчно SOL, за да покриете транзакцията и таксата му за транзакция. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате.", + "insufficient_lamports": "Нямате достатъчно SOL, за да покриете транзакцията и таксата му за транзакция. Имате нужда от поне ${solValueNeeded} sol. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате", "insufficientFundsForRentError": "Нямате достатъчно SOL, за да покриете таксата за транзакцията и наемането на сметката. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате", "introducing_cake_pay": "Запознайте се с Cake Pay!", "invalid_input": "Невалиден вход", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index d47ca932c..537695dd9 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -338,6 +338,8 @@ "incoming": "Příchozí", "incorrect_seed": "Zadaný text není správný.", "inputs": "Vstupy", + "insufficient_lamport_for_tx": "Nemáte dostatek SOL na pokrytí transakce a jejího transakčního poplatku. Laskavě přidejte do své peněženky více solu nebo snižte množství Sol, kterou odesíláte.", + "insufficient_lamports": "Nemáte dostatek SOL na pokrytí transakce a jejího transakčního poplatku. Potřebujete alespoň ${solValueNeeded} sol. Laskavě přidejte do své peněženky více SOL nebo snižte množství Sol, kterou odesíláte", "insufficientFundsForRentError": "Nemáte dostatek SOL na pokrytí transakčního poplatku a nájemného za účet. Laskavě přidejte do své peněženky více SOL nebo snižte množství Sol, kterou odesíláte", "introducing_cake_pay": "Představujeme Cake Pay!", "invalid_input": "Neplatný vstup", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index e64c3bc27..052015367 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -338,6 +338,8 @@ "incoming": "Eingehend", "incorrect_seed": "Der eingegebene Text ist ungültig.", "inputs": "Eingänge", + "insufficient_lamport_for_tx": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Bitte fügen Sie Ihrer Brieftasche mehr Sol hinzu oder reduzieren Sie die SO -Menge, die Sie senden.", + "insufficient_lamports": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Sie brauchen mindestens ${solValueNeeded} Sol. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol -Betrag", "insufficientFundsForRentError": "Sie haben nicht genug SOL, um die Transaktionsgebühr und die Miete für das Konto zu decken. Bitte fügen Sie mehr Sol zu Ihrer Brieftasche hinzu oder reduzieren Sie den von Ihnen gesendeten Sol -Betrag", "introducing_cake_pay": "Einführung von Cake Pay!", "invalid_input": "Ungültige Eingabe", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 9d7d9ad49..0f0ebd470 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -338,6 +338,8 @@ "incoming": "Incoming", "incorrect_seed": "The text entered is not valid.", "inputs": "Inputs", + "insufficient_lamport_for_tx": "You do not have enough SOL to cover the transaction and its transaction fee. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending.", + "insufficient_lamports": "You do not have enough SOL to cover the transaction and its transaction fee. You need at least ${solValueNeeded} SOL. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending", "insufficientFundsForRentError": "You do not have enough SOL to cover the transaction fee and rent for the account. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending", "introducing_cake_pay": "Introducing Cake Pay!", "invalid_input": "Invalid input", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index e7f1366a5..1e6eeae59 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -338,6 +338,8 @@ "incoming": "Entrante", "incorrect_seed": "El texto ingresado no es válido.", "inputs": "Entradas", + "insufficient_lamport_for_tx": "No tiene suficiente SOL para cubrir la transacción y su tarifa de transacción. Por favor, agregue más SOL a su billetera o reduzca la cantidad de sol que está enviando.", + "insufficient_lamports": "No tiene suficiente SOL para cubrir la transacción y su tarifa de transacción. Necesita al menos ${solValueNeeded} sol. Por favor, agregue más sol a su billetera o reduzca la cantidad de sol que está enviando", "insufficientFundsForRentError": "No tiene suficiente SOL para cubrir la tarifa de transacción y alquilar para la cuenta. Por favor, agregue más sol a su billetera o reduzca la cantidad de sol que está enviando", "introducing_cake_pay": "¡Presentamos Cake Pay!", "invalid_input": "Entrada inválida", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 7965eca12..a64a69514 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -338,6 +338,8 @@ "incoming": "Entrantes", "incorrect_seed": "Le texte entré est invalide.", "inputs": "Contributions", + "insufficient_lamport_for_tx": "Vous n'avez pas assez de sol pour couvrir la transaction et ses frais de transaction. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de Sol que vous envoyez.", + "insufficient_lamports": "Vous n'avez pas assez de sol pour couvrir la transaction et ses frais de transaction. Vous avez besoin d'au moins ${solValueNeeded} sol. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de sol que vous envoyez", "insufficientFundsForRentError": "Vous n'avez pas assez de SOL pour couvrir les frais de transaction et le loyer pour le compte. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de sol que vous envoyez", "introducing_cake_pay": "Présentation de Cake Pay !", "invalid_input": "Entrée invalide", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index d2c58971f..219b3c939 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -338,6 +338,8 @@ "incoming": "Mai shigowa", "incorrect_seed": "rubutun da aka shigar ba shi da inganci.", "inputs": "Abubuwan da ke ciki", + "insufficient_lamport_for_tx": "Ba ku da isasshen sool don rufe ma'amala da kuɗin ma'amala. Da unara ƙara ƙarin sool a cikin walat ɗinku ko rage adadin Sol ɗin da kuke aikawa.", + "insufficient_lamports": "Ba ku da isasshen sool don rufe ma'amala da kuɗin ma'amala. Kuna buƙatar aƙalla ${solValueNeeded} Sol. Da kyau ƙara ƙarin sool zuwa walat ɗinku ko rage adadin Sol ɗin da kuke aikawa", "insufficientFundsForRentError": "Ba ku da isasshen Sol don rufe kuɗin ma'amala da haya don asusun. Da kyau ƙara ƙarin sool zuwa walat ɗinku ko rage adadin Sol ɗin da kuke aikawa", "introducing_cake_pay": "Gabatar da Cake Pay!", "invalid_input": "Shigar da ba daidai ba", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index baa3925c0..b711939a4 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -338,6 +338,8 @@ "incoming": "आने वाली", "incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।", "inputs": "इनपुट", + "insufficient_lamport_for_tx": "आपके पास लेनदेन और इसके लेनदेन शुल्क को कवर करने के लिए पर्याप्त सोल नहीं है। कृपया अपने बटुए में अधिक सोल जोड़ें या आपके द्वारा भेजे जा रहे सोल राशि को कम करें।", + "insufficient_lamports": "आपके पास लेनदेन और इसके लेनदेन शुल्क को कवर करने के लिए पर्याप्त सोल नहीं है। आपको कम से कम ${solValueNeeded} सोल की आवश्यकता है। कृपया अपने बटुए में अधिक सोल जोड़ें या सोल राशि को कम करें जिसे आप भेज रहे हैं", "insufficientFundsForRentError": "आपके पास लेन -देन शुल्क और खाते के लिए किराए को कवर करने के लिए पर्याप्त सोल नहीं है। कृपया अपने बटुए में अधिक सोल जोड़ें या सोल राशि को कम करें जिसे आप भेज रहे हैं", "introducing_cake_pay": "परिचय Cake Pay!", "invalid_input": "अमान्य निवेश", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index e6b820300..401514735 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -338,6 +338,8 @@ "incoming": "Dolazno", "incorrect_seed": "Uneseni tekst nije valjan.", "inputs": "Unosi", + "insufficient_lamport_for_tx": "Nemate dovoljno SOL -a da pokriva transakciju i njegovu transakcijsku naknadu. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete.", + "insufficient_lamports": "Nemate dovoljno SOL -a da pokriva transakciju i njegovu transakcijsku naknadu. Trebate najmanje ${solValueNeeded} sol. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete", "insufficientFundsForRentError": "Nemate dovoljno SOL -a za pokrivanje naknade za transakciju i najamninu za račun. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete", "introducing_cake_pay": "Predstavljamo Cake Pay!", "invalid_input": "Pogrešan unos", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 0b8077807..b6210b5dd 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -338,6 +338,8 @@ "incoming": "Masuk", "incorrect_seed": "Teks yang dimasukkan tidak valid.", "inputs": "Input", + "insufficient_lamport_for_tx": "Anda tidak memiliki cukup SOL untuk menutupi transaksi dan biaya transaksinya. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim.", + "insufficient_lamports": "Anda tidak memiliki cukup SOL untuk menutupi transaksi dan biaya transaksinya. Anda membutuhkan setidaknya ${solValueNeeded} sol. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim", "insufficientFundsForRentError": "Anda tidak memiliki cukup SOL untuk menutupi biaya transaksi dan menyewa untuk akun tersebut. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim", "introducing_cake_pay": "Perkenalkan Cake Pay!", "invalid_input": "Masukan tidak valid", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index b7a81ef9a..fc4abf7c4 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -339,6 +339,8 @@ "incoming": "In arrivo", "incorrect_seed": "Il testo inserito non è valido.", "inputs": "Input", + "insufficient_lamport_for_tx": "Non hai abbastanza SOL per coprire la transazione e la sua quota di transazione. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando.", + "insufficient_lamports": "Non hai abbastanza SOL per coprire la transazione e la sua quota di transazione. Hai bisogno di almeno ${solValueNeeded} sol. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando", "insufficientFundsForRentError": "Non hai abbastanza SOL per coprire la tassa di transazione e l'affitto per il conto. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando", "introducing_cake_pay": "Presentazione di Cake Pay!", "invalid_input": "Inserimento non valido", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index a13a4e6f0..98495fc8b 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -339,6 +339,8 @@ "incoming": "着信", "incorrect_seed": "入力されたテキストは無効です。", "inputs": "入力", + "insufficient_lamport_for_tx": "トランザクションとその取引手数料をカバーするのに十分なSOLがありません。財布にソルを追加するか、送信するソル量を減らしてください。", + "insufficient_lamports": "トランザクションとその取引手数料をカバーするのに十分なSOLがありません。少なくとも${solValueNeeded} solが必要です。財布にソルを追加するか、送信するソル量を減らしてください", "insufficientFundsForRentError": "アカウントの取引料金とレンタルをカバーするのに十分なソルがありません。財布にソルを追加するか、送信するソル量を減らしてください", "introducing_cake_pay": "序章Cake Pay!", "invalid_input": "無効入力", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index d20546f41..60c52b21f 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -338,6 +338,8 @@ "incoming": "들어오는", "incorrect_seed": "입력하신 텍스트가 유효하지 않습니다.", "inputs": "입력", + "insufficient_lamport_for_tx": "거래 및 거래 수수료를 충당하기에 충분한 SOL이 없습니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄입니다.", + "insufficient_lamports": "거래 및 거래 수수료를 충당하기에 충분한 SOL이 없습니다. 최소 ${solValueNeeded} sol이 필요합니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄이십시오.", "insufficientFundsForRentError": "거래 수수료와 계좌 임대료를 충당하기에 충분한 SOL이 없습니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄이십시오.", "introducing_cake_pay": "소개 Cake Pay!", "invalid_input": "잘못된 입력", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 06d7cf627..42643be48 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -338,6 +338,8 @@ "incoming": "ဝင်လာ", "incorrect_seed": "ထည့်သွင်းထားသော စာသားသည် မမှန်ကန်ပါ။", "inputs": "သွင်းငေှ", + "insufficient_lamport_for_tx": "သငျသညျငွေပေးငွေယူနှင့်၎င်း၏ငွေပေးငွေယူကြေးကိုဖုံးလွှမ်းရန် sol ရှိသည်မဟုတ်ကြဘူး။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုထပ်ထည့်ပါသို့မဟုတ်သင်ပို့လွှတ်ခြင်း sol ပမာဏကိုလျှော့ချပါ။", + "insufficient_lamports": "သငျသညျငွေပေးငွေယူနှင့်၎င်း၏ငွေပေးငွေယူကြေးကိုဖုံးလွှမ်းရန် sol ရှိသည်မဟုတ်ကြဘူး။ သင်အနည်းဆုံး ${solValueNeeded} s ကိုလိုအပ်ပါတယ်။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုထပ်ထည့်ပါသို့မဟုတ်သင်ပို့နေသော sol ပမာဏကိုလျှော့ချပါ", "insufficientFundsForRentError": "သင်ငွေပေးချေမှုအခကြေးငွေကိုဖုံးအုပ်ရန်နှင့်အကောင့်ငှားရန်လုံလောက်သော sol ရှိသည်မဟုတ်ကြဘူး။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုပိုမိုထည့်ပါသို့မဟုတ်သင်ပို့ခြင်း sol ပမာဏကိုလျှော့ချပါ", "introducing_cake_pay": "Cake Pay ကို မိတ်ဆက်ခြင်း။", "invalid_input": "ထည့်သွင်းမှု မမှန်ကန်ပါ။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 78caef912..0f6149182 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -338,6 +338,8 @@ "incoming": "inkomend", "incorrect_seed": "De ingevoerde tekst is niet geldig.", "inputs": "Invoer", + "insufficient_lamport_for_tx": "U hebt niet genoeg SOL om de transactie en de transactiekosten te dekken. Voeg vriendelijk meer SOL toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt.", + "insufficient_lamports": "U hebt niet genoeg SOL om de transactie en de transactiekosten te dekken. Je hebt minstens ${solValueNeeded} sol nodig. Voeg vriendelijk meer Sol toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt", "insufficientFundsForRentError": "U hebt niet genoeg SOL om de transactiekosten en huur voor de rekening te dekken. Voeg vriendelijk meer SOL toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt", "introducing_cake_pay": "Introductie van Cake Pay!", "invalid_input": "Ongeldige invoer", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 7de435319..48d6e38f6 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -338,6 +338,8 @@ "incoming": "Przychodzące", "incorrect_seed": "Wprowadzony seed jest nieprawidłowy.", "inputs": "Wejścia", + "insufficient_lamport_for_tx": "Nie masz wystarczającej ilości SOL, aby pokryć transakcję i opłatę za transakcję. Uprzejmie dodaj więcej sol do portfela lub zmniejsz wysyłaną kwotę SOL.", + "insufficient_lamports": "Nie masz wystarczającej ilości SOL, aby pokryć transakcję i opłatę za transakcję. Potrzebujesz przynajmniej ${solValueNeeded} sol. Uprzejmie dodaj więcej sol do portfela lub zmniejsz wysyłaną kwotę SOL, którą wysyłasz", "insufficientFundsForRentError": "Nie masz wystarczającej ilości SOL, aby pokryć opłatę za transakcję i czynsz za konto. Uprzejmie dodaj więcej sol do portfela lub zmniejsz solę, którą wysyłasz", "introducing_cake_pay": "Przedstawiamy Cake Pay!", "invalid_input": "Nieprawidłowe dane wejściowe", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index a3d789cab..070f3f776 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -338,6 +338,8 @@ "incoming": "Recebidas", "incorrect_seed": "O texto digitado não é válido.", "inputs": "Entradas", + "insufficient_lamport_for_tx": "Você não tem Sol suficiente para cobrir a transação e sua taxa de transação. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você envia.", + "insufficient_lamports": "Você não tem Sol suficiente para cobrir a transação e sua taxa de transação. Você precisa de pelo menos ${solValueNeeded} sol. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você está enviando", "insufficientFundsForRentError": "Você não tem Sol suficiente para cobrir a taxa de transação e o aluguel da conta. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você envia", "introducing_cake_pay": "Apresentando o Cake Pay!", "invalid_input": "Entrada inválida", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index d84aa146f..695877c77 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -338,6 +338,8 @@ "incoming": "Входящие", "incorrect_seed": "Введённый текст некорректный.", "inputs": "Входы", + "insufficient_lamport_for_tx": "У вас недостаточно Sol, чтобы покрыть транзакцию и плату за транзакцию. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете.", + "insufficient_lamports": "У вас недостаточно Sol, чтобы покрыть транзакцию и плату за транзакцию. Вам нужен как минимум ${solValueNeeded} sol. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете", "insufficientFundsForRentError": "У вас недостаточно Sol, чтобы покрыть плату за транзакцию и аренду для счета. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете", "introducing_cake_pay": "Представляем Cake Pay!", "invalid_input": "Неверный Ввод", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 2adccb2cf..5757eed0b 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -338,6 +338,8 @@ "incoming": "ขาเข้า", "incorrect_seed": "ข้อความที่ป้อนไม่ถูกต้อง", "inputs": "อินพุต", + "insufficient_lamport_for_tx": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมการทำธุรกรรมและค่าธรรมเนียมการทำธุรกรรม กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณส่งมา", + "insufficient_lamports": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมการทำธุรกรรมและค่าธรรมเนียมการทำธุรกรรม คุณต้องการอย่างน้อย ${solValueNeeded} SOL กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณกำลังส่ง", "insufficientFundsForRentError": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมค่าธรรมเนียมการทำธุรกรรมและค่าเช่าสำหรับบัญชี กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณส่งมา", "introducing_cake_pay": "ยินดีต้อนรับสู่ Cake Pay!", "invalid_input": "อินพุตไม่ถูกต้อง", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 22093f772..7fc83afd8 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -338,6 +338,8 @@ "incoming": "Papasok", "incorrect_seed": "Ang text na ipinasok ay hindi wasto.", "inputs": "Mga input", + "insufficient_lamport_for_tx": "Wala kang sapat na SOL upang masakop ang transaksyon at ang bayad sa transaksyon nito. Mabuting magdagdag ng higit pa sa iyong pitaka o bawasan ang sol na halaga na iyong ipinapadala.", + "insufficient_lamports": "Wala kang sapat na SOL upang masakop ang transaksyon at ang bayad sa transaksyon nito. Kailangan mo ng hindi bababa sa ${solValueNeeded} sol. Mabait na magdagdag ng higit pang sol sa iyong pitaka o bawasan ang dami ng iyong ipinapadala", "insufficientFundsForRentError": "Wala kang sapat na SOL upang masakop ang fee sa transaksyon at upa para sa account. Mabait na magdagdag ng higit pa sa iyong wallet o bawasan ang halaga ng SOL na iyong ipinapadala", "introducing_cake_pay": "Pagpapakilala ng Cake Pay!", "invalid_input": "Di-wastong input", @@ -883,4 +885,4 @@ "you_will_get": "I-convert sa", "you_will_send": "I-convert mula sa", "yy": "YY" -} +} \ No newline at end of file diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index b47787bbd..4d1aa43e4 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -338,6 +338,8 @@ "incoming": "Gelen", "incorrect_seed": "Girilen metin geçerli değil.", "inputs": "Girişler", + "insufficient_lamport_for_tx": "İşlemi ve işlem ücretini karşılamak için yeterli SOL'unuz yok. Lütfen cüzdanınıza daha fazla SOL ekleyin veya gönderdiğiniz sol miktarını azaltın.", + "insufficient_lamports": "İşlemi ve işlem ücretini karşılamak için yeterli SOL'unuz yok. En az ${solValueNeeded} Sol'a ihtiyacınız var. Lütfen cüzdanınıza daha fazla sol ekleyin veya gönderdiğiniz sol miktarını azaltın", "insufficientFundsForRentError": "İşlem ücretini karşılamak ve hesap için kiralamak için yeterli SOL'nuz yok. Lütfen cüzdanınıza daha fazla sol ekleyin veya gönderdiğiniz sol miktarını azaltın", "introducing_cake_pay": "Cake Pay ile tanışın!", "invalid_input": "Geçersiz Giriş", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 328548087..22edec0d5 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -338,6 +338,8 @@ "incoming": "Вхідні", "incorrect_seed": "Введений текст невірний.", "inputs": "Вхoди", + "insufficient_lamport_for_tx": "У вас недостатньо SOL, щоб покрити транзакцію та її плату за трансакцію. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму, яку ви надсилаєте.", + "insufficient_lamports": "У вас недостатньо SOL, щоб покрити транзакцію та її плату за трансакцію. Вам потрібно щонайменше ${solValueNeeded} sol. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму Sol, яку ви надсилаєте", "insufficientFundsForRentError": "У вас недостатньо SOL, щоб покрити плату за транзакцію та оренду на рахунок. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму, яку ви надсилаєте", "introducing_cake_pay": "Представляємо Cake Pay!", "invalid_input": "Неправильні дані", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 7d794f9bb..590f344d8 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -338,6 +338,8 @@ "incoming": "آنے والا", "incorrect_seed": "درج کردہ متن درست نہیں ہے۔", "inputs": "آدانوں", + "insufficient_lamport_for_tx": "آپ کے پاس ٹرانزیکشن اور اس کے لین دین کی فیس کا احاطہ کرنے کے لئے کافی SOL نہیں ہے۔ برائے مہربانی اپنے بٹوے میں مزید سول شامل کریں یا آپ کو بھیجنے والی سول رقم کو کم کریں۔", + "insufficient_lamports": "آپ کے پاس ٹرانزیکشن اور اس کے لین دین کی فیس کا احاطہ کرنے کے لئے کافی SOL نہیں ہے۔ آپ کو کم از کم ${solValueNeeded} sol کی ضرورت ہے۔ برائے مہربانی اپنے بٹوے میں مزید SOL شامل کریں یا آپ جس SOL رقم کو بھیج رہے ہو اسے کم کریں", "insufficientFundsForRentError": "آپ کے پاس ٹرانزیکشن فیس اور اکاؤنٹ کے لئے کرایہ لینے کے ل enough اتنا SOL نہیں ہے۔ برائے مہربانی اپنے بٹوے میں مزید سول شامل کریں یا آپ کو بھیجنے والی سول رقم کو کم کریں", "introducing_cake_pay": "Cake پے کا تعارف!", "invalid_input": "غلط ان پٹ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 2150a503f..e5cf3d3f9 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -339,6 +339,8 @@ "incoming": "Wọ́n tó ń bọ̀", "incorrect_seed": "Ọ̀rọ̀ tí a tẹ̀ kì í ṣe èyí.", "inputs": "Igbewọle", + "insufficient_lamport_for_tx": "O ko ni sosi to lati bo idunadura ati idiyele iṣowo rẹ. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku sodo naa ti o \\ 'tun n firanṣẹ.", + "insufficient_lamports": "O ko ni sosi to lati bo idunadura ati idiyele iṣowo rẹ. O nilo o kere ju ${solValueNeeded}. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku soso ti o n firanṣẹ", "insufficientFundsForRentError": "O ko ni Sol kan lati bo owo isanwo naa ki o yalo fun iroyin naa. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku soso naa ti o \\ 'tun n firanṣẹ", "introducing_cake_pay": "Ẹ bá Cake Pay!", "invalid_input": "Iṣawọle ti ko tọ", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 5db53a423..25024d0ed 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -338,6 +338,8 @@ "incoming": "收到", "incorrect_seed": "输入的文字无效。", "inputs": "输入", + "insufficient_lamport_for_tx": "您没有足够的溶胶来支付交易及其交易费用。请在您的钱包中添加更多溶胶或减少您发送的溶胶量。", + "insufficient_lamports": "您没有足够的溶胶来支付交易及其交易费用。您至少需要${solValueNeeded} sol。请在您的钱包中添加更多溶胶或减少您发送的溶胶量", "insufficientFundsForRentError": "您没有足够的溶胶来支付该帐户的交易费和租金。请在钱包中添加更多溶胶或减少您发送的溶胶量", "introducing_cake_pay": "介绍 Cake Pay!", "invalid_input": "输入无效", From ec8c404086f0c87e000afb881e9c4ba600e5602b Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Sat, 17 Aug 2024 04:25:10 +0200 Subject: [PATCH 02/10] fix rosseta builds (#1593) --- scripts/macos/build_monero_all.sh | 11 +++++------ scripts/prepare_moneroc.sh | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/macos/build_monero_all.sh b/scripts/macos/build_monero_all.sh index 9f6130066..c934b4667 100755 --- a/scripts/macos/build_monero_all.sh +++ b/scripts/macos/build_monero_all.sh @@ -43,15 +43,14 @@ else WOWNERO_LIBS=" -arch ${ARCH} ${WOWNEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib" if [[ ! $(uname -m) == $ARCH ]]; then - PRC="arch -${ARCH}" + PRC="arch -${ARCH}" fi - pushd ../monero_c + pushd ../monero_c $PRC ./build_single.sh ${COIN} ${HOST} $NPROC - unxz -f ./release/${COIN}/${HOST}_libwallet2_api_c.dylib.xz - - popd - done + unxz -f ./release/${COIN}/${HOST}_libwallet2_api_c.dylib.xz + popd + done done fi diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index 2e53a54ea..94754c935 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -8,7 +8,7 @@ if [[ ! -d "monero_c" ]]; then git clone https://github.com/mrcyjanek/monero_c --branch rewrite-wip cd monero_c - git checkout bcb328a4956105dc182afd0ce2e48fe263f5f20b + git checkout 5de323b1ba7387cf73973042f06383d4dbe619f5 git reset --hard git submodule update --init --force --recursive ./apply_patches.sh monero From eef319658a1934c15768b335c7164b491de403f0 Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Sat, 17 Aug 2024 04:30:48 +0200 Subject: [PATCH 03/10] Fix legacy seeds not being displayed when polyseed is not supported (#1608) * Fix legacy seeds not being displayed when polyseed is not supported * fallback to english on Japanese, it errors with empty errorString - probably some kind of normalization issue --- cw_monero/lib/api/wallet.dart | 13 ++++++++++++- cw_monero/pubspec.lock | 9 +++++---- cw_monero/pubspec.yaml | 5 ++++- cw_wownero/lib/api/wallet.dart | 13 ++++++++++++- cw_wownero/pubspec.lock | 9 +++++---- cw_wownero/pubspec.yaml | 5 ++++- lib/src/widgets/seed_language_picker.dart | 2 +- pubspec_base.yaml | 5 ++++- 8 files changed, 47 insertions(+), 14 deletions(-) diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 973a38535..1a6e5315d 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -45,12 +45,23 @@ String getSeed() { String getSeedLegacy(String? language) { var legacy = monero.Wallet_seed(wptr!, seedOffset: ''); + switch (language) { + case "Chinese (Traditional)": language = "Chinese (simplified)"; break; + case "Chinese (Simplified)": language = "Chinese (simplified)"; break; + case "Korean": language = "English"; break; + case "Czech": language = "English"; break; + case "Japanese": language = "English"; break; + } if (monero.Wallet_status(wptr!) != 0) { monero.Wallet_setSeedLanguage(wptr!, language: language ?? "English"); legacy = monero.Wallet_seed(wptr!, seedOffset: ''); } if (monero.Wallet_status(wptr!) != 0) { - return monero.Wallet_errorString(wptr!); + final err = monero.Wallet_errorString(wptr!); + if (legacy.isNotEmpty) { + return "$err\n\n$legacy"; + } + return err; } return legacy; } diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 07c3b8876..51efd4076 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -575,10 +575,11 @@ packages: polyseed: dependency: "direct main" description: - name: polyseed - sha256: edf28042e7b0b28f97a0469aa98e6e4015937cef6b9340cd6ad2822139c95217 - url: "https://pub.dev" - source: hosted + path: "." + ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + resolved-ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + url: "https://github.com/mrcyjanek/polyseed_dart" + source: git version: "0.0.5" pool: dependency: transitive diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index b5a13a126..7f5da2621 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -19,7 +19,10 @@ dependencies: flutter_mobx: ^2.0.6+1 intl: ^0.18.0 encrypt: ^5.0.1 - polyseed: ^0.0.5 + polyseed: + git: + url: https://github.com/mrcyjanek/polyseed_dart + ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f cw_core: path: ../cw_core monero: diff --git a/cw_wownero/lib/api/wallet.dart b/cw_wownero/lib/api/wallet.dart index 2ccd560ed..0a06a9950 100644 --- a/cw_wownero/lib/api/wallet.dart +++ b/cw_wownero/lib/api/wallet.dart @@ -47,12 +47,23 @@ String getSeed() { String getSeedLegacy(String? language) { var legacy = wownero.Wallet_seed(wptr!, seedOffset: ''); + switch (language) { + case "Chinese (Traditional)": language = "Chinese (simplified)"; break; + case "Chinese (Simplified)": language = "Chinese (simplified)"; break; + case "Korean": language = "English"; break; + case "Czech": language = "English"; break; + case "Japanese": language = "English"; break; + } if (wownero.Wallet_status(wptr!) != 0) { wownero.Wallet_setSeedLanguage(wptr!, language: language ?? "English"); legacy = wownero.Wallet_seed(wptr!, seedOffset: ''); } if (wownero.Wallet_status(wptr!) != 0) { - return wownero.Wallet_errorString(wptr!); + final err = wownero.Wallet_errorString(wptr!); + if (legacy.isNotEmpty) { + return "$err\n\n$legacy"; + } + return err; } return legacy; } diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index 85d856b35..f164b3086 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -567,10 +567,11 @@ packages: polyseed: dependency: "direct main" description: - name: polyseed - sha256: edf28042e7b0b28f97a0469aa98e6e4015937cef6b9340cd6ad2822139c95217 - url: "https://pub.dev" - source: hosted + path: "." + ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + resolved-ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + url: "https://github.com/mrcyjanek/polyseed_dart" + source: git version: "0.0.5" pool: dependency: transitive diff --git a/cw_wownero/pubspec.yaml b/cw_wownero/pubspec.yaml index 7a45eb628..eb14286a9 100644 --- a/cw_wownero/pubspec.yaml +++ b/cw_wownero/pubspec.yaml @@ -19,7 +19,10 @@ dependencies: flutter_mobx: ^2.0.6+1 intl: ^0.18.0 encrypt: ^5.0.1 - polyseed: ^0.0.5 + polyseed: + git: + url: https://github.com/mrcyjanek/polyseed_dart + ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f cw_core: path: ../cw_core monero: diff --git a/lib/src/widgets/seed_language_picker.dart b/lib/src/widgets/seed_language_picker.dart index 3bb0376b1..5cb8f2fd3 100644 --- a/lib/src/widgets/seed_language_picker.dart +++ b/lib/src/widgets/seed_language_picker.dart @@ -17,7 +17,7 @@ class SeedLanguagePickerOption { final List<SeedLanguagePickerOption> seedLanguages = [ SeedLanguagePickerOption('English', S.current.seed_language_english, Image.asset('assets/images/flags/usa.png'), [SeedType.legacy, SeedType.polyseed]), - SeedLanguagePickerOption('Chinese (simplified)', S.current.seed_language_chinese, + SeedLanguagePickerOption('Chinese (Simplified)', S.current.seed_language_chinese, Image.asset('assets/images/flags/chn.png'), [SeedType.legacy, SeedType.polyseed]), SeedLanguagePickerOption('Chinese (Traditional)', S.current.seed_language_chinese_traditional, Image.asset('assets/images/flags/chn.png'), [SeedType.polyseed]), diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 567d1b210..a2f346bae 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -94,7 +94,10 @@ dependencies: # ref: main socks5_proxy: ^1.0.4 flutter_svg: ^2.0.9 - polyseed: ^0.0.5 + polyseed: + git: + url: https://github.com/mrcyjanek/polyseed_dart + ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f nostr_tools: ^1.0.9 solana: ^0.30.1 bitcoin_base: From 83ef61e92877dfaa7b506df2982d983162c8f0cc Mon Sep 17 00:00:00 2001 From: Matthew Fosse <matt@fosse.co> Date: Sat, 17 Aug 2024 19:10:27 -0400 Subject: [PATCH 04/10] Cw 565 sign messages (#1378) * version bump to 3.13.9, auth working on mac * bump flutter version in workflow file * workflow fix * test fix * downgrade flutter version * test fix * test fix * update gradle version * start working on ui for message signing * updates * sign working for a few wallet types * updates & verification for electrum currencies * nano support * sign/verify working on eth, bitcoin broken * update translations * Implement Verify Message for Monero * save [skip ci] * pub key extraction working * fixes for electrum signing * verify working for solana! * electrum still not working :( [skip ci] * electrum messages working! * fixes for updated dart version, localization file updates * remove accidental inclusion * missed some unimplemented throws * Update res/values/strings_de.arb Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> * Apply suggestions from code review Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> * review suggestions and updates [skip ci] * [skip ci] add polygon * [skip ci] merge mac-auth/update version * fix litecoin * bio auth mac fix * remove comment and change duration from 2 to 0 * cherry pick previous changes * litecoin fixes, sign form fixes, use new walletAddressPicker * support accounts * verify messages working for monero * working sign and verify messages for nano * electrum signing working [skip ci] * additional nano fixes * update translations * attempt to decode signatures with base64 * workaround for secure storage bug on mac * bump version to 3.19.5 (because breez will need this version anyways) * some code cleanup * some changess didn't get saved * just documenting the issue [skip ci] * undo accidental removal + minor code cleanup * merge conflicts * merge fixes [skip ci] * add tron support * [wip] fixing * remove duplicate references to electrum path for maintainability * fixes * minor fix * fixes * undo debug comment * update migration for all electrum based wallets * hotfixes * copy over the rest of the fixes * minor code cleanup [skip ci] * updates * electrum signing workinggit statusgit statusgit statusgit status! * copy same fixes for litecoin * litecoin fixes * add v to litecoin signatures * fix dependencies * fix bitcoin_base version * merge fix * dep override * fix conflicts with main * trial fix for android build * fixes * fix * dep fix, should build * fix signing for bitcoin cash * [skip ci] minor code cleanup * [skip ci] minor code cleanup 2 * forgot wonero, various other fixes * more fixes * fix solana (untested) --------- Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> --- cw_bitcoin/lib/electrum_wallet.dart | 73 ++++++- cw_bitcoin/lib/litecoin_wallet.dart | 131 +++++++++++- cw_bitcoin/pubspec.yaml | 8 +- .../lib/src/bitcoin_cash_wallet.dart | 11 +- cw_bitcoin_cash/pubspec.yaml | 8 +- cw_core/lib/wallet_base.dart | 5 +- cw_evm/lib/evm_chain_wallet.dart | 20 +- cw_evm/pubspec.yaml | 2 + cw_monero/lib/api/wallet.dart | 4 + cw_monero/lib/monero_wallet.dart | 8 + cw_nano/lib/nano_block_info_response.dart | 37 ++++ cw_nano/lib/nano_client.dart | 87 ++++++-- cw_nano/lib/nano_wallet.dart | 25 ++- cw_nano/pubspec.lock | 8 +- cw_nano/pubspec.yaml | 3 +- cw_solana/lib/solana_wallet.dart | 54 ++++- cw_tron/lib/tron_wallet.dart | 14 +- cw_wownero/lib/api/wallet.dart | 4 + cw_wownero/lib/wownero_wallet.dart | 7 + lib/bitcoin/cw_bitcoin.dart | 4 +- lib/buy/dfx/dfx_buy_provider.dart | 4 +- lib/buy/robinhood/robinhood_buy_provider.dart | 6 +- lib/di.dart | 16 +- lib/router.dart | 14 ++ lib/routes.dart | 2 + .../cake_pay_confirm_purchase_card_page.dart | 18 +- .../dashboard/pages/cake_features_page.dart | 14 ++ lib/src/screens/dashboard/sign_page.dart | 202 ++++++++++++++++++ .../screens/dashboard/widgets/sign_form.dart | 98 +++++++++ .../dashboard/widgets/verify_form.dart | 92 ++++++++ .../screens/receive/address_list_page.dart | 31 +++ lib/src/screens/receive/receive_page.dart | 104 +-------- .../screens/receive/widgets/address_list.dart | 120 +++++++++++ lib/src/widgets/address_text_field.dart | 194 ++++++++++------- .../dashboard/dashboard_view_model.dart | 36 +++- lib/view_model/dashboard/sign_view_model.dart | 55 +++++ .../wallet_address_list_view_model.dart | 9 + lib/view_model/wallet_creation_vm.dart | 8 +- pubspec_base.yaml | 6 +- res/values/strings_ar.arb | 8 + res/values/strings_bg.arb | 8 + res/values/strings_cs.arb | 8 + res/values/strings_de.arb | 8 + res/values/strings_en.arb | 8 + res/values/strings_es.arb | 8 + res/values/strings_fr.arb | 8 + res/values/strings_ha.arb | 8 + res/values/strings_hi.arb | 8 + res/values/strings_hr.arb | 8 + res/values/strings_id.arb | 8 + res/values/strings_it.arb | 8 + res/values/strings_ja.arb | 8 + res/values/strings_ko.arb | 8 + res/values/strings_my.arb | 8 + res/values/strings_nl.arb | 8 + res/values/strings_pl.arb | 8 + res/values/strings_pt.arb | 8 + res/values/strings_ru.arb | 8 + res/values/strings_th.arb | 8 + res/values/strings_tl.arb | 8 + res/values/strings_tr.arb | 8 + res/values/strings_uk.arb | 8 + res/values/strings_ur.arb | 8 + res/values/strings_yo.arb | 8 + res/values/strings_zh.arb | 8 + 65 files changed, 1479 insertions(+), 271 deletions(-) create mode 100644 cw_nano/lib/nano_block_info_response.dart create mode 100644 lib/src/screens/dashboard/sign_page.dart create mode 100644 lib/src/screens/dashboard/widgets/sign_form.dart create mode 100644 lib/src/screens/dashboard/widgets/verify_form.dart create mode 100644 lib/src/screens/receive/address_list_page.dart create mode 100644 lib/src/screens/receive/widgets/address_list.dart create mode 100644 lib/view_model/dashboard/sign_view_model.dart diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 9dc8de083..8f2360f26 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -42,6 +42,7 @@ import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:rxdart/subjects.dart'; +import 'package:http/http.dart' as http; import 'package:sp_scanner/sp_scanner.dart'; part 'electrum_wallet.g.dart'; @@ -132,6 +133,7 @@ abstract class ElectrumWalletBase final String? _mnemonic; Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0)); + Bip32Slip10Secp256k1 get sideHd => accountHD.childKey(Bip32KeyIndex(1)); final EncryptionFileUtils encryptionFileUtils; final String? passphrase; @@ -591,7 +593,7 @@ abstract class ElectrumWalletBase } final derivationPath = - "${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}" + "${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? electrum_path)}" "/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}" "/${utx.bitcoinAddressRecord.index}"; publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath); @@ -1869,11 +1871,70 @@ abstract class ElectrumWalletBase ? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index : null; final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index)); - final priv = ECPrivate.fromWif( - WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer), - netVersion: network.wifNetVer, - ); - return priv.signMessage(StringUtils.encode(message)); + final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex()); + + String messagePrefix = '\x18Bitcoin Signed Message:\n'; + final hexEncoded = priv.signMessage(utf8.encode(message), messagePrefix: messagePrefix); + final decodedSig = hex.decode(hexEncoded); + return base64Encode(decodedSig); + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) async { + if (address == null) { + return false; + } + + List<int> sigDecodedBytes = []; + + if (signature.endsWith('=')) { + sigDecodedBytes = base64.decode(signature); + } else { + sigDecodedBytes = hex.decode(signature); + } + + if (sigDecodedBytes.length != 64 && sigDecodedBytes.length != 65) { + throw ArgumentException( + "signature must be 64 bytes without recover-id or 65 bytes with recover-id"); + } + + String messagePrefix = '\x18Bitcoin Signed Message:\n'; + final messageHash = QuickCrypto.sha256Hash( + BitcoinSignerUtils.magicMessage(utf8.encode(message), messagePrefix)); + + List<int> correctSignature = + sigDecodedBytes.length == 65 ? sigDecodedBytes.sublist(1) : List.from(sigDecodedBytes); + List<int> rBytes = correctSignature.sublist(0, 32); + List<int> sBytes = correctSignature.sublist(32); + final sig = ECDSASignature(BigintUtils.fromBytes(rBytes), BigintUtils.fromBytes(sBytes)); + + List<int> possibleRecoverIds = [0, 1]; + + final baseAddress = addressTypeFromStr(address, network); + + for (int recoveryId in possibleRecoverIds) { + final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId); + + final recoveredPub = ECPublic.fromBytes(pubKey!.toBytes()); + + String? recoveredAddress; + + if (baseAddress is P2pkAddress) { + recoveredAddress = recoveredPub.toP2pkAddress().toAddress(network); + } else if (baseAddress is P2pkhAddress) { + recoveredAddress = recoveredPub.toP2pkhAddress().toAddress(network); + } else if (baseAddress is P2wshAddress) { + recoveredAddress = recoveredPub.toP2wshAddress().toAddress(network); + } else if (baseAddress is P2wpkhAddress) { + recoveredAddress = recoveredPub.toP2wpkhAddress().toAddress(network); + } + + if (recoveredAddress == address) { + return true; + } + } + + return false; } Future<void> _setInitialHeight() async { diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index d8c04dba6..890d98342 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -1,6 +1,9 @@ -import 'package:bip39/bip39.dart' as bip39; +import 'dart:convert'; + import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; +import 'package:blockchain_utils/signer/ecdsa_signing_key.dart'; +import 'package:bip39/bip39.dart' as bip39; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; @@ -17,6 +20,9 @@ import 'package:cw_core/wallet_keys_file.dart'; import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; +import 'package:bitcoin_base/src/crypto/keypair/sign_utils.dart'; +import 'package:pointycastle/ecc/api.dart'; +import 'package:pointycastle/ecc/curves/secp256k1.dart'; part 'litecoin_wallet.g.dart'; @@ -167,4 +173,127 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return 0; } + + @override + Future<String> signMessage(String message, {String? address = null}) async { + final index = address != null + ? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index + : null; + final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index)); + final priv = ECPrivate.fromHex(HD.privateKey.privKey.toHex()); + + final privateKey = ECDSAPrivateKey.fromBytes( + priv.toBytes(), + Curves.generatorSecp256k1, + ); + + final signature = + signLitecoinMessage(utf8.encode(message), privateKey: privateKey, bipPrive: priv.prive); + + return base64Encode(signature); + } + + List<int> _magicPrefix(List<int> message, List<int> messagePrefix) { + final encodeLength = IntUtils.encodeVarint(message.length); + + return [...messagePrefix, ...encodeLength, ...message]; + } + + List<int> signLitecoinMessage(List<int> message, + {required ECDSAPrivateKey privateKey, required Bip32PrivateKey bipPrive}) { + String messagePrefix = '\x19Litecoin Signed Message:\n'; + final messageHash = QuickCrypto.sha256Hash(magicMessage(message, messagePrefix)); + final signingKey = EcdsaSigningKey(privateKey); + ECDSASignature ecdsaSign = + signingKey.signDigestDeterminstic(digest: messageHash, hashFunc: () => SHA256()); + final n = Curves.generatorSecp256k1.order! >> 1; + BigInt newS; + if (ecdsaSign.s.compareTo(n) > 0) { + newS = Curves.generatorSecp256k1.order! - ecdsaSign.s; + } else { + newS = ecdsaSign.s; + } + final rawSig = ECDSASignature(ecdsaSign.r, newS); + final rawSigBytes = rawSig.toBytes(BitcoinSignerUtils.baselen); + + final pub = bipPrive.publicKey; + final ECDomainParameters curve = ECCurve_secp256k1(); + final point = curve.curve.decodePoint(pub.point.toBytes()); + + final rawSigEc = ECSignature(rawSig.r, rawSig.s); + + final recId = SignUtils.findRecoveryId( + SignUtils.getHexString(messageHash, offset: 0, length: messageHash.length), + rawSigEc, + Uint8List.fromList(pub.uncompressed), + ); + + final v = recId + 27 + (point!.isCompressed ? 4 : 0); + + final combined = Uint8List.fromList([v, ...rawSigBytes]); + + return combined; + } + + List<int> magicMessage(List<int> message, String messagePrefix) { + final prefixBytes = StringUtils.encode(messagePrefix); + final magic = _magicPrefix(message, prefixBytes); + return QuickCrypto.sha256Hash(magic); + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) async { + if (address == null) { + return false; + } + + List<int> sigDecodedBytes = []; + + if (signature.endsWith('=')) { + sigDecodedBytes = base64.decode(signature); + } else { + sigDecodedBytes = hex.decode(signature); + } + + if (sigDecodedBytes.length != 64 && sigDecodedBytes.length != 65) { + throw ArgumentException( + "litecoin signature must be 64 bytes without recover-id or 65 bytes with recover-id"); + } + + String messagePrefix = '\x19Litecoin Signed Message:\n'; + final messageHash = QuickCrypto.sha256Hash(magicMessage(utf8.encode(message), messagePrefix)); + + List<int> correctSignature = + sigDecodedBytes.length == 65 ? sigDecodedBytes.sublist(1) : List.from(sigDecodedBytes); + List<int> rBytes = correctSignature.sublist(0, 32); + List<int> sBytes = correctSignature.sublist(32); + final sig = ECDSASignature(BigintUtils.fromBytes(rBytes), BigintUtils.fromBytes(sBytes)); + + List<int> possibleRecoverIds = [0, 1]; + + final baseAddress = addressTypeFromStr(address, network); + + for (int recoveryId in possibleRecoverIds) { + final pubKey = sig.recoverPublicKey(messageHash, Curves.generatorSecp256k1, recoveryId); + final recoveredPub = ECPublic.fromBytes(pubKey!.toBytes()); + + String? recoveredAddress; + + if (baseAddress is P2pkAddress) { + recoveredAddress = recoveredPub.toP2pkAddress().toAddress(network); + } else if (baseAddress is P2pkhAddress) { + recoveredAddress = recoveredPub.toP2pkhAddress().toAddress(network); + } else if (baseAddress is P2wshAddress) { + recoveredAddress = recoveredPub.toP2wshAddress().toAddress(network); + } else if (baseAddress is P2wpkhAddress) { + recoveredAddress = recoveredPub.toP2wpkhAddress().toAddress(network); + } + + if (recoveredAddress == address) { + return true; + } + } + + return false; + } } diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 449833220..2af1ac54e 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -25,10 +25,6 @@ dependencies: ref: Add-Support-For-OP-Return-data rxdart: ^0.27.5 cryptography: ^2.0.5 - bitcoin_base: - git: - url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v4 blockchain_utils: git: url: https://github.com/cake-tech/blockchain_utils @@ -57,6 +53,10 @@ dependency_overrides: url: https://github.com/cake-tech/ledger-flutter.git ref: cake-v3 watcher: ^1.1.0 + bitcoin_base: + git: + url: https://github.com/cake-tech/bitcoin_base + ref: cake-update-v5 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart index a59569ae6..5659528c0 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart @@ -202,11 +202,12 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { @override Future<String> signMessage(String message, {String? address = null}) async { - final index = address != null - ? walletAddresses.allAddresses - .firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address)) - .index - : null; + int? index; + try { + index = address != null + ? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index + : null; + } catch (_) {} final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index)); final priv = ECPrivate.fromWif( WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer), diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 3728bafc5..64bd38b1d 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -25,10 +25,6 @@ dependencies: git: url: https://github.com/cake-tech/bitbox-flutter.git ref: Add-Support-For-OP-Return-data - bitcoin_base: - git: - url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v4 blockchain_utils: git: url: https://github.com/cake-tech/blockchain_utils @@ -43,6 +39,10 @@ dev_dependencies: dependency_overrides: watcher: ^1.1.0 + bitcoin_base: + git: + url: https://github.com/cake-tech/bitcoin_base + ref: cake-update-v5 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart index f7af15224..14ba898a7 100644 --- a/cw_core/lib/wallet_base.dart +++ b/cw_core/lib/wallet_base.dart @@ -69,7 +69,6 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans int calculateEstimatedFee(TransactionPriority priority, int? amount); - // void fetchTransactionsAsync( // void Function(TransactionType transaction) onTransactionLoaded, // {void Function() onFinished}); @@ -92,7 +91,9 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans Future<void> renameWalletFiles(String newWalletName); - Future<String> signMessage(String message, {String? address = null}) => throw UnimplementedError(); + Future<String> signMessage(String message, {String? address = null}); + + Future<bool> verifyMessage(String message, String signature, {String? address = null}); bool? isTestnet; } diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index 80a366e6f..bbf972f0d 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -35,6 +35,7 @@ import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:web3dart/crypto.dart'; import 'package:web3dart/web3dart.dart'; +import 'package:eth_sig_util/eth_sig_util.dart'; import 'evm_chain_transaction_info.dart'; import 'evm_erc20_balance.dart'; @@ -500,7 +501,7 @@ abstract class EVMChainWalletBase } final methodSignature = - transactionInput.length >= 10 ? transactionInput.substring(0, 10) : null; + transactionInput.length >= 10 ? transactionInput.substring(0, 10) : null; return methodSignatureToType[methodSignature]; } @@ -692,8 +693,21 @@ abstract class EVMChainWalletBase } @override - Future<String> signMessage(String message, {String? address}) async => - bytesToHex(await _evmChainPrivateKey.signPersonalMessage(ascii.encode(message))); + Future<String> signMessage(String message, {String? address}) async { + return bytesToHex(await _evmChainPrivateKey.signPersonalMessage(ascii.encode(message))); + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address}) async { + if (address == null) { + return false; + } + final recoveredAddress = EthSigUtil.recoverPersonalSignature( + message: ascii.encode(message), + signature: signature, + ); + return recoveredAddress.toUpperCase() == address.toUpperCase(); + } Web3Client? getWeb3Client() => _client.getWeb3Client(); diff --git a/cw_evm/pubspec.yaml b/cw_evm/pubspec.yaml index b24e375a7..3e12834b1 100644 --- a/cw_evm/pubspec.yaml +++ b/cw_evm/pubspec.yaml @@ -13,6 +13,8 @@ dependencies: flutter: sdk: flutter web3dart: ^2.7.1 + eth_sig_util: ^0.0.9 + erc20: ^1.0.1 bip39: ^1.0.6 bip32: ^2.0.0 hex: ^0.2.0 diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 1a6e5315d..b493e536e 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -316,3 +316,7 @@ Future<bool> trustedDaemon() async => monero.Wallet_trustedDaemon(wptr!); String signMessage(String message, {String address = ""}) { return monero.Wallet_signMessage(wptr!, message: message, address: address); } + +bool verifyMessage(String message, String address, String signature) { + return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature); +} \ No newline at end of file diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index 31e09ca2d..f5fa0ec7e 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -783,4 +783,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, final useAddress = address ?? ""; return monero_wallet.signMessage(message, address: useAddress); } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) async { + if (address == null) return false; + + return monero_wallet.verifyMessage(message, address, signature); + } + } diff --git a/cw_nano/lib/nano_block_info_response.dart b/cw_nano/lib/nano_block_info_response.dart new file mode 100644 index 000000000..d2f000b9d --- /dev/null +++ b/cw_nano/lib/nano_block_info_response.dart @@ -0,0 +1,37 @@ +class BlockContentsResponse { + String type; + String account; + String previous; + String representative; + String balance; + String link; + String linkAsAccount; + String signature; + String work; + + BlockContentsResponse({ + required this.type, + required this.account, + required this.previous, + required this.representative, + required this.balance, + required this.link, + required this.linkAsAccount, + required this.signature, + required this.work, + }); + + factory BlockContentsResponse.fromJson(Map<String, dynamic> json) { + return BlockContentsResponse( + type: json['type'] as String, + account: json['account'] as String, + previous: json['previous'] as String, + representative: json['representative'] as String, + balance: json['balance'] as String, + link: json['link'] as String, + linkAsAccount: json['link_as_account'] as String, + signature: json['signature'] as String, + work: json['work'] as String, + ); + } +} diff --git a/cw_nano/lib/nano_client.dart b/cw_nano/lib/nano_client.dart index 8d8bef13d..478a6c125 100644 --- a/cw_nano/lib/nano_client.dart +++ b/cw_nano/lib/nano_client.dart @@ -2,11 +2,11 @@ import 'dart:async'; import 'dart:convert'; import 'package:cw_core/nano_account_info_response.dart'; +import 'package:cw_nano/nano_block_info_response.dart'; import 'package:cw_core/n2_node.dart'; import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_transaction_model.dart'; import 'package:http/http.dart' as http; -import 'package:nanodart/nanodart.dart'; import 'package:cw_core/node.dart'; import 'package:nanoutil/nanoutil.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -111,6 +111,27 @@ class NanoClient { } } + Future<BlockContentsResponse?> getBlockContents(String block) async { + try { + final response = await http.post( + _node!.uri, + headers: CAKE_HEADERS, + body: jsonEncode( + { + "action": "block_info", + "json_block": "true", + "hash": block, + }, + ), + ); + final data = await jsonDecode(response.body); + return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>); + } catch (e) { + print("error while getting block info $e"); + return null; + } + } + Future<String> changeRep({ required String privateKey, required String repAddress, @@ -135,8 +156,8 @@ class NanoClient { }; // sign the change block: - final String hash = NanoBlocks.computeStateHash( - NanoAccountType.NANO, + final String hash = NanoSignatures.computeStateHash( + NanoBasedCurrency.NANO, changeBlock["account"]!, changeBlock["previous"]!, changeBlock["representative"]!, @@ -248,7 +269,7 @@ class NanoClient { } final String representative = infoResponse.representative; // link = destination address: - final String link = NanoAccounts.extractPublicKey(destinationAddress); + final String link = NanoDerivations.addressToPublicKey(destinationAddress); final String linkAsAccount = destinationAddress; // construct the send block: @@ -262,8 +283,8 @@ class NanoClient { }; // sign the send block: - final String hash = NanoBlocks.computeStateHash( - NanoAccountType.NANO, + final String hash = NanoSignatures.computeStateHash( + NanoBasedCurrency.NANO, sendBlock["account"]!, sendBlock["previous"]!, sendBlock["representative"]!, @@ -285,7 +306,6 @@ class NanoClient { Future<void> receiveBlock({ required String blockHash, - required String source, required String amountRaw, required String destinationAddress, required String privateKey, @@ -310,15 +330,56 @@ class NanoClient { representative = infoData.representative; } + if ((BigInt.tryParse(amountRaw) ?? BigInt.zero) <= BigInt.zero) { + throw Exception("amountRaw must be greater than zero"); + } + + BlockContentsResponse? frontierContents; + + if (!openBlock) { + // get the block info of the frontier block: + frontierContents = await getBlockContents(frontier); + + if (frontierContents == null) { + throw Exception("error while getting frontier block info"); + } + + final String frontierHash = NanoSignatures.computeStateHash( + NanoBasedCurrency.NANO, + frontierContents.account, + frontierContents.previous, + frontierContents.representative, + BigInt.parse(frontierContents.balance), + frontierContents.link, + ); + + bool valid = await NanoSignatures.verify( + frontierHash, + frontierContents.signature, + destinationAddress, + ); + + if (!valid) { + throw Exception( + "Frontier block signature is invalid! Potentially malicious block detected!"); + } + } + // first get the account balance: - final BigInt currentBalance = (await getBalance(destinationAddress)).currentBalance; + late BigInt currentBalance; + if (!openBlock) { + currentBalance = BigInt.parse(frontierContents!.balance); + } else { + currentBalance = BigInt.zero; + } final BigInt txAmount = BigInt.parse(amountRaw); final BigInt balanceAfterTx = currentBalance + txAmount; // link = send block hash: final String link = blockHash; // this "linkAsAccount" is meaningless: - final String linkAsAccount = NanoAccounts.createAccount(NanoAccountType.NANO, blockHash); + final String linkAsAccount = + NanoDerivations.publicKeyToAddress(blockHash, currency: NanoBasedCurrency.NANO); // construct the receive block: Map<String, String> receiveBlock = { @@ -332,8 +393,8 @@ class NanoClient { }; // sign the receive block: - final String hash = NanoBlocks.computeStateHash( - NanoAccountType.NANO, + final String hash = NanoSignatures.computeStateHash( + NanoBasedCurrency.NANO, receiveBlock["account"]!, receiveBlock["previous"]!, receiveBlock["representative"]!, @@ -345,7 +406,7 @@ class NanoClient { // get PoW for the receive block: String? work; if (openBlock) { - work = await requestWork(NanoAccounts.extractPublicKey(destinationAddress)); + work = await requestWork(NanoDerivations.addressToPublicKey(destinationAddress)); } else { work = await requestWork(frontier); } @@ -409,10 +470,8 @@ class NanoClient { for (final blockHash in blocks.keys) { final block = blocks[blockHash]; final String amountRaw = block["amount"] as String; - final String source = block["source"] as String; await receiveBlock( blockHash: blockHash, - source: source, amountRaw: amountRaw, privateKey: privateKey, destinationAddress: destinationAddress, diff --git a/cw_nano/lib/nano_wallet.dart b/cw_nano/lib/nano_wallet.dart index cba8d09a0..700710c2e 100644 --- a/cw_nano/lib/nano_wallet.dart +++ b/cw_nano/lib/nano_wallet.dart @@ -27,7 +27,6 @@ import 'package:cw_nano/nano_wallet_addresses.dart'; import 'package:cw_nano/nano_wallet_keys.dart'; import 'package:cw_nano/pending_nano_transaction.dart'; import 'package:mobx/mobx.dart'; -import 'package:nanodart/nanodart.dart'; import 'package:nanoutil/nanoutil.dart'; part 'nano_wallet.g.dart'; @@ -107,7 +106,6 @@ abstract class NanoWalletBase if (_derivationType == DerivationType.unknown) { _derivationType = DerivationType.nano; } - final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd"; // our "mnemonic" is actually a hex form seed: if (!_mnemonic.contains(' ')) { @@ -122,8 +120,10 @@ abstract class NanoWalletBase _hexSeed = await NanoDerivations.hdMnemonicListToSeed(_mnemonic.split(' ')); } } - NanoDerivationType derivationType = - type == "standard" ? NanoDerivationType.STANDARD : NanoDerivationType.HD; + + final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd"; + NanoDerivationType derivationType = NanoDerivations.stringToType(type); + _privateKey = await NanoDerivations.universalSeedToPrivate( _hexSeed!, index: 0, @@ -216,8 +216,8 @@ abstract class NanoWalletBase balanceAfterTx: runningBalance, previousHash: previousHash, ); - previousHash = NanoBlocks.computeStateHash( - NanoAccountType.NANO, + previousHash = NanoSignatures.computeStateHash( + NanoBasedCurrency.NANO, block["account"]!, block["previous"]!, block["representative"]!, @@ -535,4 +535,17 @@ abstract class NanoWalletBase // Delete old name's dir and files await Directory(currentDirPath).delete(recursive: true); } + + @override + Future<String> signMessage(String message, {String? address = null}) async { + return NanoSignatures.signMessage(message, privateKey!); + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) async { + if (address == null) { + return false; + } + return await NanoSignatures.verifyMessage(message, signature, address); + } } diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index bbe909199..ef9de14f9 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -513,7 +513,7 @@ packages: source: hosted version: "2.3.0" nanodart: - dependency: "direct main" + dependency: transitive description: name: nanodart sha256: "4b2f42d60307b54e8cf384d6193a567d07f8efd773858c0d5948246153c13282" @@ -524,11 +524,11 @@ packages: dependency: "direct main" description: path: "." - ref: c37e72817cf0a28162f43124f79661d6c8e0098f - resolved-ref: c37e72817cf0a28162f43124f79661d6c8e0098f + ref: c01a9c552917008d8fbc6b540db657031625b04f + resolved-ref: c01a9c552917008d8fbc6b540db657031625b04f url: "https://github.com/perishllc/nanoutil.git" source: git - version: "1.0.0" + version: "1.0.3" package_config: dependency: transitive description: diff --git a/cw_nano/pubspec.yaml b/cw_nano/pubspec.yaml index 6fae6a895..3ddd9769e 100644 --- a/cw_nano/pubspec.yaml +++ b/cw_nano/pubspec.yaml @@ -15,7 +15,6 @@ dependencies: mobx: ^2.0.7+4 bip39: ^1.0.6 bip32: ^2.0.0 - nanodart: ^2.0.0 decimal: ^2.3.3 libcrypto: ^0.2.2 ed25519_hd_key: ^2.2.0 @@ -25,7 +24,7 @@ dependencies: nanoutil: git: url: https://github.com/perishllc/nanoutil.git - ref: c37e72817cf0a28162f43124f79661d6c8e0098f + ref: c01a9c552917008d8fbc6b540db657031625b04f cw_core: path: ../cw_core diff --git a/cw_solana/lib/solana_wallet.dart b/cw_solana/lib/solana_wallet.dart index 66b8bca42..4e69db3b8 100644 --- a/cw_solana/lib/solana_wallet.dart +++ b/cw_solana/lib/solana_wallet.dart @@ -32,6 +32,8 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:solana/base58.dart'; import 'package:solana/metaplex.dart' as metaplex; import 'package:solana/solana.dart'; +import 'package:solana/src/crypto/ed25519_hd_keypair.dart'; +import 'package:cryptography/cryptography.dart'; part 'solana_wallet.g.dart'; @@ -571,17 +573,59 @@ abstract class SolanaWalletBase }); } - Future<String> signSolanaMessage(String message) async { + @override + Future<String> signMessage(String message, {String? address}) async { // Convert the message to bytes final messageBytes = utf8.encode(message); // Sign the message bytes with the wallet's private key - final signature = await _walletKeyPair!.sign(messageBytes); + final signature = (await _walletKeyPair!.sign(messageBytes)).toString(); - // Convert the signature to a hexadecimal string - final hex = HEX.encode(signature.bytes); + return HEX.encode(utf8.encode(signature)).toUpperCase(); + } - return hex; + List<List<int>> bytesFromSigString(String signatureString) { + final regex = RegExp(r'Signature\(\[(.+)\], publicKey: (.+)\)'); + final match = regex.firstMatch(signatureString); + + if (match != null) { + final bytesString = match.group(1)!; + final base58EncodedPublicKeyString = match.group(2)!; + final sigBytes = bytesString.split(', ').map(int.parse).toList(); + + List<int> pubKeyBytes = base58decode(base58EncodedPublicKeyString); + + return [sigBytes, pubKeyBytes]; + } else { + throw const FormatException('Invalid Signature string format'); + } + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address}) async { + String signatureString = utf8.decode(HEX.decode(signature)); + + List<List<int>> bytes = bytesFromSigString(signatureString); + + final messageBytes = utf8.encode(message); + final sigBytes = bytes[0]; + final pubKeyBytes = bytes[1]; + + if (address == null) { + return false; + } + + // make sure the address derived from the public key provided matches the one we expect + final pub = Ed25519HDPublicKey(pubKeyBytes); + if (address != pub.toBase58()) { + return false; + } + + return await verifySignature( + message: messageBytes, + signature: sigBytes, + publicKey: Ed25519HDPublicKey(pubKeyBytes), + ); } SolanaClient? get solanaClient => _client.getSolanaClient; diff --git a/cw_tron/lib/tron_wallet.dart b/cw_tron/lib/tron_wallet.dart index 7dc43b4bb..f5841d894 100644 --- a/cw_tron/lib/tron_wallet.dart +++ b/cw_tron/lib/tron_wallet.dart @@ -580,8 +580,18 @@ abstract class TronWalletBase } @override - Future<String> signMessage(String message, {String? address}) async => - _tronPrivateKey.signPersonalMessage(ascii.encode(message)); + Future<String> signMessage(String message, {String? address}) async { + return _tronPrivateKey.signPersonalMessage(ascii.encode(message)); + } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address}) async { + if (address == null) { + return false; + } + TronPublicKey pubKey = TronPublicKey.fromPersonalSignature(ascii.encode(message), signature)!; + return pubKey.toAddress().toString() == address; + } String getTronBase58AddressFromHex(String hexAddress) => TronAddress(hexAddress).toAddress(); diff --git a/cw_wownero/lib/api/wallet.dart b/cw_wownero/lib/api/wallet.dart index 0a06a9950..56f54dfac 100644 --- a/cw_wownero/lib/api/wallet.dart +++ b/cw_wownero/lib/api/wallet.dart @@ -320,3 +320,7 @@ Future<bool> trustedDaemon() async => wownero.Wallet_trustedDaemon(wptr!); String signMessage(String message, {String address = ""}) { return wownero.Wallet_signMessage(wptr!, message: message, address: address); } + +bool verifyMessage(String message, String address, String signature) { + return wownero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature); +} \ No newline at end of file diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart index 85f5e4b2f..c3f4bcb69 100644 --- a/cw_wownero/lib/wownero_wallet.dart +++ b/cw_wownero/lib/wownero_wallet.dart @@ -743,4 +743,11 @@ abstract class WowneroWalletBase final useAddress = address ?? ""; return wownero_wallet.signMessage(message, address: useAddress); } + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) async { + if (address == null) return false; + + return wownero_wallet.verifyMessage(message, address, signature); + } } diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 989cd2b35..e87773f97 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -275,7 +275,7 @@ class CWBitcoin extends Bitcoin { return [DerivationType.bip39, DerivationType.electrum]; } - int _countOccurrences(String str, String charToCount) { + int _countCharOccurrences(String str, String charToCount) { int count = 0; for (int i = 0; i < str.length; i++) { if (str[i] == charToCount) { @@ -330,7 +330,7 @@ class CWBitcoin extends Bitcoin { ); String balancePath = dInfoCopy.derivationPath!; - int derivationDepth = _countOccurrences(balancePath, "/"); + int derivationDepth = _countCharOccurrences(balancePath, '/'); // for BIP44 if (derivationDepth == 3 || derivationDepth == 1) { diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart index 2a7e2ab13..b3ed72498 100644 --- a/lib/buy/dfx/dfx_buy_provider.dart +++ b/lib/buy/dfx/dfx_buy_provider.dart @@ -124,12 +124,12 @@ class DFXBuyProvider extends BuyProvider { switch (wallet.type) { case WalletType.ethereum: case WalletType.polygon: - return wallet.signMessage(message); + return await wallet.signMessage(message); case WalletType.monero: case WalletType.litecoin: case WalletType.bitcoin: case WalletType.bitcoinCash: - return wallet.signMessage(message, address: walletAddress); + return await wallet.signMessage(message, address: walletAddress); default: throw Exception("WalletType is not available for DFX ${wallet.type}"); } diff --git a/lib/buy/robinhood/robinhood_buy_provider.dart b/lib/buy/robinhood/robinhood_buy_provider.dart index ab58754dd..2d809772e 100644 --- a/lib/buy/robinhood/robinhood_buy_provider.dart +++ b/lib/buy/robinhood/robinhood_buy_provider.dart @@ -37,15 +37,15 @@ class RobinhoodBuyProvider extends BuyProvider { String get _apiSecret => secrets.exchangeHelperApiKey; - Future<String> getSignature(String message) { + Future<String> getSignature(String message) async { switch (wallet.type) { case WalletType.ethereum: case WalletType.polygon: - return wallet.signMessage(message); + return await wallet.signMessage(message); case WalletType.litecoin: case WalletType.bitcoin: case WalletType.bitcoinCash: - return wallet.signMessage(message, address: wallet.walletAddresses.address); + return await wallet.signMessage(message, address: wallet.walletAddresses.address); default: throw Exception("WalletType is not available for Robinhood ${wallet.type}"); } diff --git a/lib/di.dart b/lib/di.dart index 7c22e809c..1967c9227 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -30,6 +30,12 @@ import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/contact_record.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/parse_address_from_domain.dart'; +import 'package:cake_wallet/src/screens/receive/address_list_page.dart'; +import 'package:cake_wallet/view_model/link_view_model.dart'; +import 'package:cake_wallet/tron/tron.dart'; +import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; +import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart'; +import 'package:cw_core/receive_page_option.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/qr_view_data.dart'; import 'package:cake_wallet/entities/template.dart'; @@ -159,7 +165,6 @@ import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/node.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart'; -import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; @@ -179,7 +184,6 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart'; import 'package:cake_wallet/store/templates/send_template_store.dart'; import 'package:cake_wallet/store/wallet_list_store.dart'; import 'package:cake_wallet/store/yat/yat_store.dart'; -import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/view_model/auth_view_model.dart'; import 'package:cake_wallet/view_model/backup_view_model.dart'; import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart'; @@ -193,7 +197,6 @@ import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; -import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart'; @@ -224,7 +227,6 @@ import 'package:cake_wallet/view_model/wallet_unlock_loadable_view_model.dart'; import 'package:cake_wallet/view_model/wallet_unlock_verifiable_view_model.dart'; import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; @@ -853,6 +855,8 @@ Future<void> setup({ getIt.registerFactoryParam<ContactPage, ContactRecord?, void>( (ContactRecord? contact, _) => ContactPage(getIt.get<ContactViewModel>(param1: contact))); + getIt.registerFactory(() => AddressListPage(getIt.get<WalletAddressListViewModel>())); + getIt.registerFactory(() { final appStore = getIt.get<AppStore>(); return NodeListViewModel(_nodeSource, appStore); @@ -1271,9 +1275,11 @@ Future<void> setup({ getIt.registerFactory( () => WalletConnectConnectionsView(web3walletService: getIt.get<Web3WalletService>())); - + getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>())); getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>())); + getIt.registerFactory(() => SignViewModel(getIt.get<AppStore>().wallet!)); + _isSetupFinished = true; } diff --git a/lib/router.dart b/lib/router.dart index 498077511..25af39043 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -27,6 +27,7 @@ import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart'; import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart'; +import 'package:cake_wallet/src/screens/dashboard/sign_page.dart'; import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart'; import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart'; import 'package:cake_wallet/src/screens/exchange/exchange_page.dart'; @@ -42,6 +43,8 @@ import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart'; import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart'; import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart'; import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart'; +import 'package:cake_wallet/src/screens/receive/address_list_page.dart'; +import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart'; @@ -99,6 +102,7 @@ import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; @@ -465,6 +469,9 @@ Route<dynamic> createRoute(RouteSettings settings) { return MaterialPageRoute<void>( builder: (_) => getIt.get<ContactListPage>(param1: selectedCurrency)); + case Routes.pickerWalletAddress: + return MaterialPageRoute<void>(builder: (_) => getIt.get<AddressListPage>()); + case Routes.addressBookAddContact: return CupertinoPageRoute<void>( builder: (_) => getIt.get<ContactPage>(param1: settings.arguments as ContactRecord?)); @@ -696,6 +703,13 @@ Route<dynamic> createRoute(RouteSettings settings) { case Routes.torPage: return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>()); + case Routes.signPage: + return MaterialPageRoute<void>( + builder: (_) => SignPage( + getIt.get<SignViewModel>(), + ), + ); + case Routes.connectDevices: final params = settings.arguments as ConnectDevicePageParams; return MaterialPageRoute<void>( diff --git a/lib/routes.dart b/lib/routes.dart index caa7eb39e..9c421cab5 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -31,6 +31,7 @@ class Routes { static const nanoAccountCreation = '/nano_account_new'; static const addressBook = '/address_book'; static const pickerAddressBook = '/picker_address_book'; + static const pickerWalletAddress = '/picker_wallet_address'; static const addressBookAddContact = '/address_book_add_contact'; static const showKeys = '/show_keys'; static const exchangeConfirm = '/exchange_confirm'; @@ -103,5 +104,6 @@ class Routes { static const nftDetailsPage = '/nft_details_page'; static const importNFTPage = '/import_nft_page'; static const torPage = '/tor_page'; + static const signPage = '/sign_page'; static const connectDevices = '/device/connect'; } diff --git a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart index 02ddf037d..81f6a354f 100644 --- a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart @@ -322,31 +322,31 @@ class CakePayBuyCardDetailPage extends BasePage { await showPopUp<void>( context: context, - builder: (_) { + builder: (popupContext) { return Observer( builder: (_) => ConfirmSendingAlert( - alertTitle: S.of(context).confirm_sending, - paymentId: S.of(context).payment_id, + alertTitle: S.of(popupContext).confirm_sending, + paymentId: S.of(popupContext).payment_id, paymentIdValue: order?.orderId, expirationTime: cakePayPurchaseViewModel.formattedRemainingTime, onDispose: () => _handleDispose(disposer), - amount: S.of(context).send_amount, + amount: S.of(popupContext).send_amount, amountValue: pendingTransaction.amountFormatted, fiatAmountValue: cakePayPurchaseViewModel.sendViewModel.pendingTransactionFiatAmountFormatted, - fee: S.of(context).send_fee, + fee: S.of(popupContext).send_fee, feeValue: pendingTransaction.feeFormatted, feeFiatAmount: cakePayPurchaseViewModel.sendViewModel.pendingTransactionFeeFiatAmountFormatted, feeRate: pendingTransaction.feeRate, outputs: cakePayPurchaseViewModel.sendViewModel.outputs, - rightButtonText: S.of(context).send, - leftButtonText: S.of(context).cancel, + rightButtonText: S.of(popupContext).send, + leftButtonText: S.of(popupContext).cancel, actionRightButton: () async { - Navigator.of(context).pop(); + Navigator.of(popupContext).pop(); await cakePayPurchaseViewModel.sendViewModel.commitTransaction(); }, - actionLeftButton: () => Navigator.of(context).pop())); + actionLeftButton: () => Navigator.of(popupContext).pop())); }, ); } diff --git a/lib/src/screens/dashboard/pages/cake_features_page.dart b/lib/src/screens/dashboard/pages/cake_features_page.dart index b034fb799..0c953c892 100644 --- a/lib/src/screens/dashboard/pages/cake_features_page.dart +++ b/lib/src/screens/dashboard/pages/cake_features_page.dart @@ -8,6 +8,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -64,6 +65,19 @@ class CakeFeaturesPage extends StatelessWidget { subTitle: S.of(context).nanogpt_subtitle, onTap: () => _launchUrl("cake.nano-gpt.com"), ), + SizedBox(height: 20), + Observer( + builder: (context) { + if (!dashboardViewModel.hasSignMessages) { + return const SizedBox(); + } + return DashBoardRoundedCardWidget( + onTap: () => Navigator.of(context).pushNamed(Routes.signPage), + title: S.current.sign_verify_message, + subTitle: S.current.sign_verify_message_sub, + ); + }, + ), ], ), ), diff --git a/lib/src/screens/dashboard/sign_page.dart b/lib/src/screens/dashboard/sign_page.dart new file mode 100644 index 000000000..05cf63728 --- /dev/null +++ b/lib/src/screens/dashboard/sign_page.dart @@ -0,0 +1,202 @@ +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/sign_form.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/verify_form.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; +import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:keyboard_actions/keyboard_actions.dart'; +import 'package:mobx/mobx.dart'; +import 'package:smooth_page_indicator/smooth_page_indicator.dart'; + +class SignPage extends BasePage { + SignPage(this.signViewModel) + : signFormKey = GlobalKey<SignFormState>(), + verifyFormKey = GlobalKey<VerifyFormState>(), + _pages = [], + _controller = PageController(initialPage: 0) { + _pages.add(SignForm( + key: signFormKey, + type: signViewModel.wallet.type, + includeAddress: signViewModel.signIncludesAddress, + )); + _pages.add(VerifyForm( + key: verifyFormKey, + type: signViewModel.wallet.type, + )); + } + + @override + Widget middle(BuildContext context) => Observer( + builder: (_) => Text( + S.current.sign_verify_title, + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + fontFamily: 'Lato', + color: titleColor(context), + ), + )); + + final SignViewModel signViewModel; + final PageController _controller; + final List<Widget> _pages; + final GlobalKey<SignFormState> signFormKey; + final GlobalKey<VerifyFormState> verifyFormKey; + bool _isEffectsInstalled = false; + + @override + Widget body(BuildContext context) { + _setEffects(context); + + return KeyboardActions( + config: KeyboardActionsConfig( + keyboardActionsPlatform: KeyboardActionsPlatform.IOS, + keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor, + nextFocus: false, + actions: [ + KeyboardActionsItem( + focusNode: FocusNode(), + toolbarButtons: [(_) => KeyboardDoneButton()], + ) + ], + ), + child: Container( + height: 0, + color: Theme.of(context).colorScheme.background, + child: Center( + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: PageView.builder( + onPageChanged: (page) { + signViewModel.isSigning = page == 0; + }, + controller: _controller, + itemCount: _pages.length, + itemBuilder: (_, index) => SingleChildScrollView(child: _pages[index]), + ), + ), + if (_pages.length > 1) + Padding( + padding: EdgeInsets.only(top: 10), + child: SmoothPageIndicator( + controller: _controller, + count: _pages.length, + effect: ColorTransitionEffect( + spacing: 6.0, + radius: 6.0, + dotWidth: 6.0, + dotHeight: 6.0, + dotColor: Theme.of(context).hintColor.withOpacity(0.5), + activeDotColor: Theme.of(context).hintColor, + ), + ), + ), + Padding( + padding: EdgeInsets.only(top: 20, bottom: 24, left: 24, right: 24), + child: Column( + children: [ + Observer( + builder: (context) { + return LoadingPrimaryButton( + onPressed: () async { + await _confirmForm(context); + }, + text: signViewModel.isSigning + ? S.current.sign_message + : S.current.verify_message, + color: Theme.of(context) + .extension<WalletListTheme>()! + .createNewWalletButtonBackgroundColor, + textColor: Theme.of(context) + .extension<WalletListTheme>()! + .restoreWalletButtonTextColor, + isLoading: signViewModel.state is IsExecutingState, + isDisabled: signViewModel.state is IsExecutingState, + ); + }, + ), + ], + ), + ) + ], + ), + ), + ), + ), + ); + } + + void _setEffects(BuildContext context) async { + if (_isEffectsInstalled) { + return; + } + _isEffectsInstalled = true; + + reaction((_) => signViewModel.state, (ExecutionState state) { + if (state is FailureState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp<void>( + context: context, + builder: (_) { + return AlertWithOneAction( + alertTitle: S.current.error, + alertContent: state.error, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ); + }); + }); + } + if (state is ExecutedSuccessfullyState) { + if (signViewModel.isSigning) { + signFormKey.currentState!.signatureController.text = state.payload as String; + } else { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp<void>( + context: context, + builder: (_) { + return AlertWithOneAction( + alertTitle: S.current.successful, + alertContent: S.current.message_verified, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ); + }); + }); + } + } + }); + } + + Future<void> _confirmForm(BuildContext context) async { + FocusManager.instance.primaryFocus?.unfocus(); + + if (signViewModel.isSigning) { + String message = signFormKey.currentState!.messageController.text; + String? address; + if (signViewModel.signIncludesAddress) { + address = signFormKey.currentState!.addressController.text; + } + await signViewModel.sign(message, address: address); + } else { + String message = verifyFormKey.currentState!.messageController.text; + String signature = verifyFormKey.currentState!.signatureController.text; + String address = verifyFormKey.currentState!.addressController.text; + await signViewModel.verify(message, signature, address: address); + } + } +} diff --git a/lib/src/screens/dashboard/widgets/sign_form.dart b/lib/src/screens/dashboard/widgets/sign_form.dart new file mode 100644 index 000000000..c0f8ba328 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/sign_form.dart @@ -0,0 +1,98 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/widgets/address_text_field.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class SignForm extends StatefulWidget { + SignForm({ + Key? key, + required this.type, + required this.includeAddress, + }) : super(key: key); + + final WalletType type; + final bool includeAddress; + + @override + SignFormState createState() => SignFormState(); +} + +class SignFormState extends State<SignForm> { + SignFormState() + : formKey = GlobalKey<FormState>(), + messageController = TextEditingController(), + addressController = TextEditingController(), + signatureController = TextEditingController(); + + final TextEditingController messageController; + final TextEditingController addressController; + final TextEditingController signatureController; + final GlobalKey<FormState> formKey; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 24, right: 24), + child: Column( + children: [ + Form( + key: formKey, + child: Column( + children: [ + AddressTextField( + controller: messageController, + placeholder: S.current.message, + options: [AddressTextFieldOption.paste], + buttonColor: Theme.of(context).hintColor, + ), + if (widget.includeAddress) ...[ + const SizedBox(height: 20), + AddressTextField( + controller: addressController, + options: [ + AddressTextFieldOption.paste, + AddressTextFieldOption.walletAddresses + ], + buttonColor: Theme.of(context).hintColor, + onSelectedContact: (contact) { + addressController.text = contact.address; + }, + selectedCurrency: walletTypeToCryptoCurrency(widget.type), + ), + ], + ], + )), + const SizedBox(height: 20), + GestureDetector( + onTap: () async { + final text = signatureController.text; + if (text.isEmpty) { + return; + } + Clipboard.setData(ClipboardData(text: text)); + showBar<void>(context, S.of(context).transaction_details_copied(text)); + }, + child: BaseTextFormField( + enabled: false, + controller: signatureController, + hintText: S.current.signature, + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/dashboard/widgets/verify_form.dart b/lib/src/screens/dashboard/widgets/verify_form.dart new file mode 100644 index 000000000..d59261494 --- /dev/null +++ b/lib/src/screens/dashboard/widgets/verify_form.dart @@ -0,0 +1,92 @@ +import 'package:cake_wallet/core/wallet_name_validator.dart'; +import 'package:cake_wallet/entities/generate_name.dart'; +import 'package:cake_wallet/entities/seed_type.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/widgets/address_text_field.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/src/widgets/seed_language_picker.dart'; +import 'package:cake_wallet/src/widgets/seed_widget.dart'; +import 'package:cake_wallet/themes/extensions/address_theme.dart'; +import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/seed_type_view_model.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:mobx/mobx.dart'; +import 'package:polyseed/polyseed.dart'; + +class VerifyForm extends StatefulWidget { + VerifyForm({ + Key? key, + required this.type, + }) : super(key: key); + + final WalletType type; + + @override + VerifyFormState createState() => VerifyFormState(); +} + +class VerifyFormState extends State<VerifyForm> { + VerifyFormState() + : formKey = GlobalKey<FormState>(), + messageController = TextEditingController(), + addressController = TextEditingController(), + signatureController = TextEditingController(); + + final TextEditingController messageController; + final TextEditingController addressController; + final TextEditingController signatureController; + final GlobalKey<FormState> formKey; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 24, right: 24), + child: Form( + key: formKey, + child: Column( + children: [ + AddressTextField( + controller: messageController, + placeholder: S.current.message, + options: [AddressTextFieldOption.paste], + buttonColor: Theme.of(context).hintColor, + ), + const SizedBox(height: 20), + AddressTextField( + controller: addressController, + options: [AddressTextFieldOption.paste, AddressTextFieldOption.walletAddresses], + buttonColor: Theme.of(context).hintColor, + onSelectedContact: (contact) { + addressController.text = contact.address; + }, + selectedCurrency: walletTypeToCryptoCurrency(widget.type), + ), + const SizedBox(height: 20), + AddressTextField( + controller: signatureController, + placeholder: S.current.signature, + options: [AddressTextFieldOption.paste], + buttonColor: Theme.of(context).hintColor, + ), + ], + ), + ), + ); + } +} diff --git a/lib/src/screens/receive/address_list_page.dart b/lib/src/screens/receive/address_list_page.dart new file mode 100644 index 000000000..5f6794715 --- /dev/null +++ b/lib/src/screens/receive/address_list_page.dart @@ -0,0 +1,31 @@ +import 'package:cake_wallet/src/screens/receive/widgets/address_list.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; + +class AddressListPage extends BasePage { + AddressListPage(this.addressListViewModel); + + final WalletAddressListViewModel addressListViewModel; + + @override + String get title => S.current.accounts_subaddresses; + + @override + Widget body(BuildContext context) { + return SingleChildScrollView( + child: Column( + children: <Widget>[ + AddressList( + addressListViewModel: addressListViewModel, + onSelect: (String address) async { + Navigator.of(context).pop(address); + }, + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart index 03524ef79..724e5c3bd 100644 --- a/lib/src/screens/receive/receive_page.dart +++ b/lib/src/screens/receive/receive_page.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart'; +import 'package:cake_wallet/src/screens/receive/widgets/address_list.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/themes/extensions/balance_page_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; @@ -122,108 +123,7 @@ class ReceivePage extends BasePage { amountController: _amountController, isLight: currentTheme.type == ThemeType.light), ), - Observer( - builder: (_) => ListView.separated( - padding: EdgeInsets.all(0), - separatorBuilder: (context, _) => const HorizontalSectionDivider(), - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: addressListViewModel.items.length, - itemBuilder: (context, index) { - final item = addressListViewModel.items[index]; - Widget cell = Container(); - - if (item is WalletAccountListHeader) { - cell = HeaderTile( - showTrailingButton: true, - walletAddressListViewModel: addressListViewModel, - trailingButtonTap: () async { - if (addressListViewModel.type == WalletType.monero || - addressListViewModel.type == WalletType.wownero || - addressListViewModel.type == WalletType.haven) { - await showPopUp<void>( - context: context, - builder: (_) => getIt.get<MoneroAccountListPage>()); - } else { - await showPopUp<void>( - context: context, - builder: (_) => getIt.get<NanoAccountListPage>()); - } - }, - title: S.of(context).accounts, - trailingIcon: Icon( - Icons.arrow_forward_ios, - size: 14, - color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor, - )); - } - - if (item is WalletAddressListHeader) { - final hasTitle = item.title != null; - - cell = HeaderTile( - title: hasTitle ? item.title! : S.of(context).addresses, - walletAddressListViewModel: addressListViewModel, - showTrailingButton: - !addressListViewModel.isAutoGenerateSubaddressEnabled && !hasTitle, - showSearchButton: true, - trailingButtonTap: () => - Navigator.of(context).pushNamed(Routes.newSubaddress), - trailingIcon: hasTitle - ? null - : Icon( - Icons.add, - size: 20, - color: - Theme.of(context).extension<ReceivePageTheme>()!.iconsColor, - ), - ); - } - - if (item is WalletAddressListItem) { - cell = Observer(builder: (_) { - final isCurrent = item.address == addressListViewModel.address.address; - final backgroundColor = isCurrent - ? Theme.of(context) - .extension<ReceivePageTheme>()! - .currentTileBackgroundColor - : Theme.of(context) - .extension<ReceivePageTheme>()! - .tilesBackgroundColor; - final textColor = isCurrent - ? Theme.of(context) - .extension<ReceivePageTheme>()! - .currentTileTextColor - : Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor; - - return AddressCell.fromItem( - item, - isCurrent: isCurrent, - hasBalance: addressListViewModel.isElectrumWallet, - backgroundColor: backgroundColor, - textColor: textColor, - onTap: item.isOneTimeReceiveAddress == true - ? null - : (_) => addressListViewModel.setAddress(item), - onEdit: item.isOneTimeReceiveAddress == true || item.isPrimary - ? null - : () => Navigator.of(context) - .pushNamed(Routes.newSubaddress, arguments: item), - onDelete: !addressListViewModel.isSilentPayments || item.isPrimary - ? null - : () => addressListViewModel.deleteAddress(item), - ); - }); - } - - return index != 0 - ? cell - : ClipRRect( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(30), topRight: Radius.circular(30)), - child: cell, - ); - })), + AddressList(addressListViewModel: addressListViewModel), Padding( padding: EdgeInsets.fromLTRB(24, 24, 24, 32), child: Text( diff --git a/lib/src/screens/receive/widgets/address_list.dart b/lib/src/screens/receive/widgets/address_list.dart new file mode 100644 index 000000000..8dfbedec1 --- /dev/null +++ b/lib/src/screens/receive/widgets/address_list.dart @@ -0,0 +1,120 @@ +import 'package:cake_wallet/di.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart'; +import 'package:cake_wallet/src/screens/nano_accounts/nano_account_list_page.dart'; +import 'package:cake_wallet/src/screens/receive/widgets/address_cell.dart'; +import 'package:cake_wallet/src/screens/receive/widgets/header_tile.dart'; +import 'package:cake_wallet/src/widgets/section_divider.dart'; +import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_header.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; + +class AddressList extends StatelessWidget { + const AddressList({ + super.key, + required this.addressListViewModel, + this.onSelect, + }); + + final WalletAddressListViewModel addressListViewModel; + final Function(String)? onSelect; + + @override + Widget build(BuildContext context) { + bool editable = onSelect == null; + return Observer( + builder: (_) => ListView.separated( + padding: EdgeInsets.all(0), + separatorBuilder: (context, _) => const HorizontalSectionDivider(), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: addressListViewModel.items.length, + itemBuilder: (context, index) { + final item = addressListViewModel.items[index]; + Widget cell = Container(); + + if (item is WalletAccountListHeader) { + cell = HeaderTile( + showTrailingButton: true, + walletAddressListViewModel: addressListViewModel, + trailingButtonTap: () async { + if (addressListViewModel.type == WalletType.monero || + addressListViewModel.type == WalletType.haven) { + await showPopUp<void>( + context: context, builder: (_) => getIt.get<MoneroAccountListPage>()); + } else { + await showPopUp<void>( + context: context, builder: (_) => getIt.get<NanoAccountListPage>()); + } + }, + title: S.of(context).accounts, + trailingIcon: Icon( + Icons.arrow_forward_ios, + size: 14, + color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor, + )); + } + + if (item is WalletAddressListHeader) { + cell = HeaderTile( + title: S.of(context).addresses, + walletAddressListViewModel: addressListViewModel, + showTrailingButton: !addressListViewModel.isAutoGenerateSubaddressEnabled, + showSearchButton: true, + trailingButtonTap: () => Navigator.of(context).pushNamed(Routes.newSubaddress), + trailingIcon: Icon( + Icons.add, + size: 20, + color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor, + )); + } + + if (item is WalletAddressListItem) { + cell = Observer(builder: (_) { + final isCurrent = item.address == addressListViewModel.address.address && editable; + final backgroundColor = isCurrent + ? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor + : Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor; + final textColor = isCurrent + ? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor + : Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor; + + return AddressCell.fromItem( + item, + isCurrent: isCurrent, + hasBalance: addressListViewModel.isElectrumWallet, + backgroundColor: backgroundColor, + textColor: textColor, + onTap: (_) { + if (onSelect != null) { + onSelect!(item.address); + return; + } + addressListViewModel.setAddress(item); + }, + onEdit: editable + ? () => Navigator.of(context).pushNamed(Routes.newSubaddress, arguments: item) + : null, + ); + }); + } + + return index != 0 + ? cell + : ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(30), topRight: Radius.circular(30)), + child: cell, + ); + }, + ), + ); + } +} diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index f79da8069..f229ea8ef 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -12,7 +12,7 @@ import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/utils/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart'; -enum AddressTextFieldOption { paste, qrCode, addressBook } +enum AddressTextFieldOption { paste, qrCode, addressBook, walletAddresses } class AddressTextField extends StatelessWidget { AddressTextField( @@ -34,6 +34,7 @@ class AddressTextField extends StatelessWidget { this.validator, this.onPushPasteButton, this.onPushAddressBookButton, + this.onPushAddressPickerButton, this.onSelectedContact, this.selectedCurrency}); @@ -56,6 +57,7 @@ class AddressTextField extends StatelessWidget { final FocusNode? focusNode; final Function(BuildContext context)? onPushPasteButton; final Function(BuildContext context)? onPushAddressBookButton; + final Function(BuildContext context)? onPushAddressPickerButton; final Function(ContactBase contact)? onSelectedContact; final CryptoCurrency? selectedCurrency; @@ -70,16 +72,13 @@ class AddressTextField extends StatelessWidget { enabled: isActive, controller: controller, focusNode: focusNode, - style: textStyle ?? TextStyle( fontSize: 16, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor), decoration: InputDecoration( - suffixIcon: SizedBox( width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length), ), - hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor), hintText: placeholder ?? S.current.widgets_address, focusedBorder: isBorderExist @@ -104,90 +103,122 @@ class AddressTextField extends StatelessWidget { top: 2, right: 0, child: SizedBox( - width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length), + width: + (prefixIconWidth * options.length) + (spaceBetweenPrefixIcons * options.length), child: Row( mainAxisAlignment: responsiveLayoutUtil.shouldRenderMobileUI ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end, children: [ - SizedBox(width: 5), if (this.options.contains(AddressTextFieldOption.paste)) ...[ + SizedBox(width: 5), Container( - width: prefixIconWidth, - height: prefixIconHeight, - padding: EdgeInsets.only(top: 0), - child: Semantics( - label: S.of(context).paste, - child: InkWell( - onTap: () async => _pasteAddress(context), - child: Container( - padding: EdgeInsets.all(8), - decoration: BoxDecoration( - color: buttonColor ?? - Theme.of(context).dialogTheme.backgroundColor, - borderRadius: BorderRadius.all(Radius.circular(6))), - child: Image.asset( - 'assets/images/paste_ios.png', - color: iconColor ?? - Theme.of(context) - .extension<SendPageTheme>()! - .textFieldButtonIconColor, - )), - ), - )), + width: prefixIconWidth, + height: prefixIconHeight, + padding: EdgeInsets.only(top: 0), + child: Semantics( + label: S.of(context).paste, + child: InkWell( + onTap: () async => _pasteAddress(context), + child: Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: + buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(6))), + child: Image.asset( + 'assets/images/paste_ios.png', + color: iconColor ?? + Theme.of(context) + .extension<SendPageTheme>()! + .textFieldButtonIconColor, + )), + ), + ), + ), ], if (this.options.contains(AddressTextFieldOption.qrCode) && DeviceInfo.instance.isMobile) ...[ - Container( - width: prefixIconWidth, - height: prefixIconHeight, - padding: EdgeInsets.only(top: 0), - child: Semantics( - label: S.of(context).scan_qr_code, - child: InkWell( - onTap: () async => _presentQRScanner(context), - child: Container( - padding: EdgeInsets.all(8), - decoration: BoxDecoration( - color: buttonColor ?? - Theme.of(context).dialogTheme.backgroundColor, - borderRadius: BorderRadius.all(Radius.circular(6))), - child: Image.asset( - 'assets/images/qr_code_icon.png', - color: iconColor ?? - Theme.of(context) - .extension<SendPageTheme>()! - .textFieldButtonIconColor, - )), - ), - )) - ] else SizedBox(width: 5), - if (this.options.contains(AddressTextFieldOption.addressBook)) ...[ Container( - width: prefixIconWidth, - height: prefixIconHeight, - padding: EdgeInsets.only(top: 0), - child: Semantics( - label: S.of(context).address_book, - child: InkWell( - onTap: () async => _presetAddressBookPicker(context), - child: Container( - padding: EdgeInsets.all(8), - decoration: BoxDecoration( - color: buttonColor ?? - Theme.of(context).dialogTheme.backgroundColor, - borderRadius: BorderRadius.all(Radius.circular(6))), - child: Image.asset( - 'assets/images/open_book.png', - color: iconColor ?? - Theme.of(context) - .extension<SendPageTheme>()! - .textFieldButtonIconColor, - )), - ), - )) - ] + width: prefixIconWidth, + height: prefixIconHeight, + padding: EdgeInsets.only(top: 0), + child: Semantics( + label: S.of(context).scan_qr_code, + child: InkWell( + onTap: () async => _presentQRScanner(context), + child: Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: + buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(6))), + child: Image.asset( + 'assets/images/qr_code_icon.png', + color: iconColor ?? + Theme.of(context) + .extension<SendPageTheme>()! + .textFieldButtonIconColor, + )), + ), + ), + ), + ], + if (this.options.contains(AddressTextFieldOption.addressBook)) ...[ + SizedBox(width: 5), + Container( + width: prefixIconWidth, + height: prefixIconHeight, + padding: EdgeInsets.only(top: 0), + child: Semantics( + label: S.of(context).address_book, + child: InkWell( + onTap: () async => _presetAddressBookPicker(context), + child: Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: + buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(6))), + child: Image.asset( + 'assets/images/open_book.png', + color: iconColor ?? + Theme.of(context) + .extension<SendPageTheme>()! + .textFieldButtonIconColor, + )), + ), + ), + ), + ], + if (this.options.contains(AddressTextFieldOption.walletAddresses)) ...[ + SizedBox(width: 5), + Container( + width: prefixIconWidth, + height: prefixIconHeight, + padding: EdgeInsets.only(top: 0), + child: Semantics( + label: S.of(context).address_book, + child: InkWell( + onTap: () async => _presetWalletAddressPicker(context), + child: Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: + buttonColor ?? Theme.of(context).dialogTheme.backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(6))), + child: Image.asset( + 'assets/images/open_book.png', + color: iconColor ?? + Theme.of(context) + .extension<SendPageTheme>()! + .textFieldButtonIconColor, + )), + ), + ), + ) + ], ], ), )) @@ -197,7 +228,7 @@ class AddressTextField extends StatelessWidget { Future<void> _presentQRScanner(BuildContext context) async { bool isCameraPermissionGranted = - await PermissionHandler.checkPermission(Permission.camera, context); + await PermissionHandler.checkPermission(Permission.camera, context); if (!isCameraPermissionGranted) return; final code = await presentQRScanner(); if (code.isEmpty) { @@ -224,6 +255,15 @@ class AddressTextField extends StatelessWidget { } } + Future<void> _presetWalletAddressPicker(BuildContext context) async { + final address = await Navigator.of(context).pushNamed(Routes.pickerWalletAddress); + + if (address is String) { + controller?.text = address; + onPushAddressPickerButton?.call(context); + } + } + Future<void> _pasteAddress(BuildContext context) async { final clipboard = await Clipboard.getData('text/plain'); final address = clipboard?.text ?? ''; diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index e98412dce..56a0e061b 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -182,7 +182,8 @@ abstract class DashboardViewModelBase with Store { final _accountTransactions = _wallet.transactionHistory.transactions.values .where((tx) => - wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id) + wow.wownero!.getTransactionInfoAccountId(tx) == + wow.wownero!.getCurrentAccount(wallet).id) .toList(); final sortedTransactions = [..._accountTransactions]; @@ -482,6 +483,27 @@ abstract class DashboardViewModelBase with Store { @computed bool get hasPowNodes => wallet.type == WalletType.nano || wallet.type == WalletType.banano; + @computed + bool get hasSignMessages { + switch (wallet.type) { + case WalletType.monero: + case WalletType.litecoin: + case WalletType.bitcoin: + case WalletType.bitcoinCash: + case WalletType.ethereum: + case WalletType.polygon: + case WalletType.solana: + case WalletType.nano: + case WalletType.banano: + case WalletType.tron: + case WalletType.wownero: + return true; + case WalletType.haven: + case WalletType.none: + return false; + } + } + bool get showRepWarning { if (wallet.type != WalletType.nano) { return false; @@ -575,7 +597,8 @@ abstract class DashboardViewModelBase with Store { } if (wallet.type == WalletType.wownero) { - return wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id; + return wow.wownero!.getTransactionInfoAccountId(tx) == + wow.wownero!.getCurrentAccount(wallet).id; } return true; @@ -600,8 +623,8 @@ abstract class DashboardViewModelBase with Store { .getTransactionHistory(wallet) .transactions .values - .where( - (tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id) + .where((tx) => + monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id) .toList(); transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem( @@ -613,8 +636,9 @@ abstract class DashboardViewModelBase with Store { .getTransactionHistory(wallet) .transactions .values - .where( - (tx) => wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id) + .where((tx) => + wow.wownero!.getTransactionInfoAccountId(tx) == + wow.wownero!.getCurrentAccount(wallet).id) .toList(); transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem( diff --git a/lib/view_model/dashboard/sign_view_model.dart b/lib/view_model/dashboard/sign_view_model.dart new file mode 100644 index 000000000..5b1b4fc00 --- /dev/null +++ b/lib/view_model/dashboard/sign_view_model.dart @@ -0,0 +1,55 @@ +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; + +part 'sign_view_model.g.dart'; + +class SignViewModel = SignViewModelBase with _$SignViewModel; + +abstract class SignViewModelBase with Store { + SignViewModelBase(this.wallet) : state = InitialExecutionState(); + + final WalletBase wallet; + + @observable + ExecutionState state; + + @observable + bool isSigning = true; + + bool get signIncludesAddress => [ + WalletType.monero, + WalletType.bitcoin, + WalletType.bitcoinCash, + WalletType.litecoin, + WalletType.haven, + ].contains(wallet.type); + + @action + Future<void> sign(String message, {String? address}) async { + state = IsExecutingState(); + try { + final signature = await wallet.signMessage(message, address: address); + state = ExecutedSuccessfullyState(payload: signature); + } catch (e) { + state = FailureState(e.toString()); + } + } + + @action + Future<void> verify(String message, String signature, {String? address}) async { + state = IsExecutingState(); + try { + final sig = await wallet.verifyMessage(message, signature, address: address); + if (sig) { + state = ExecutedSuccessfullyState(); + } else { + state = FailureState(S.current.signature_invalid_error); + } + } catch (e) { + state = FailureState(e.toString()); + } + } +} diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 6c274bb7b..0bd936720 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -6,6 +6,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/monero/monero.dart'; +import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/solana/solana.dart'; import 'package:cake_wallet/store/app_store.dart'; @@ -438,6 +439,14 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress)); } + if (wallet.type == WalletType.nano) { + addressList.add(WalletAddressListItem( + isPrimary: true, + name: null, + address: wallet.walletAddresses.address, + )); + } + if (wallet.type == WalletType.tron) { final primaryAddress = tron!.getAddress(wallet); diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index 5a9a1d093..e14934986 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -117,9 +117,7 @@ abstract class WalletCreationVMBase with Store { DerivationInfo? getDefaultDerivation() { switch (this.type) { case WalletType.nano: - return DerivationInfo( - derivationType: DerivationType.nano, - ); + return DerivationInfo(derivationType: DerivationType.nano); case WalletType.bitcoin: case WalletType.litecoin: return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first; @@ -131,9 +129,7 @@ abstract class WalletCreationVMBase with Store { DerivationInfo? getCommonRestoreDerivation() { switch (this.type) { case WalletType.nano: - return DerivationInfo( - derivationType: DerivationType.nano, - ); + return DerivationInfo(derivationType: DerivationType.nano); case WalletType.bitcoin: return DerivationInfo( derivationType: DerivationType.bip39, diff --git a/pubspec_base.yaml b/pubspec_base.yaml index a2f346bae..07dc7f5af 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -103,7 +103,7 @@ dependencies: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: cake-update-v4 + ref: cake-update-v5 ledger_flutter: ^1.0.1 hashlib: 1.12.0 @@ -138,6 +138,10 @@ dependency_overrides: url: https://github.com/cake-tech/web3dart.git ref: cake flutter_secure_storage_platform_interface: 1.0.2 + bitcoin_base: + git: + url: https://github.com/cake-tech/bitcoin_base + ref: cake-update-v5 flutter_icons: image_path: "assets/images/app_logo.png" diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index a73067383..f84f6102b 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -370,6 +370,7 @@ "max_value": "الحد الأقصى: ${value} ${currency}", "memo": "مذكرة:", "message": "ﺔﻟﺎﺳﺭ", + "message_verified": "تم التحقق من الرسالة بنجاح", "methods": " ﻕﺮﻃُ", "min_amount": "الحد الأدنى: ${value}", "min_value": "الحد الأدنى: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "اظهار السييد / المفاتيح", "show_market_place": "إظهار السوق", "show_seed": "عرض السييد", + "sign_message": "تسجيل رسالة", "sign_up": "اشتراك", + "sign_verify_message": "توقيع أو التحقق من الرسالة", + "sign_verify_message_sub": "قم بتوقيع أو التحقق من رسالة باستخدام المفتاح الخاص بك", + "sign_verify_title": "تسجيل / تحقق", + "signature": "إمضاء", + "signature_invalid_error": "التوقيع غير صالح للرسالة المقدمة", "signTransaction": " ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ", "signup_for_card_accept_terms": "قم بالتسجيل للحصول على البطاقة وقبول الشروط.", "silent_payments": "مدفوعات صامتة", @@ -822,6 +829,7 @@ "value_type": "نوع القيمة", "variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة", "verification": "تَحَقّق", + "verify_message": "تحقق من الرسالة", "verify_with_2fa": "تحقق مع Cake 2FA", "version": "الإصدار ${currentVersion}", "view_all": "مشاهدة الكل", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index b60cbc55c..0b6b688bb 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -370,6 +370,7 @@ "max_value": "Макс: ${value} ${currency}", "memo": "Мемо:", "message": "Съобщение", + "message_verified": "Съобщението беше успешно проверено", "methods": "Методи", "min_amount": "Мин: ${value}", "min_value": "Мин: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Покажи seed/keys", "show_market_place": "Покажи пазар", "show_seed": "Покажи seed", + "sign_message": "Съобщение за подписване", "sign_up": "Регистрация", + "sign_verify_message": "Подпишете или проверете съобщението", + "sign_verify_message_sub": "Подпишете или проверете съобщение с помощта на вашия личен ключ", + "sign_verify_title": "Подпишете / проверете", + "signature": "Подпис", + "signature_invalid_error": "Подписът не е валиден за даденото съобщение", "signTransaction": "Подпишете транзакция", "signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.", "silent_payments": "Мълчаливи плащания", @@ -822,6 +829,7 @@ "value_type": "Тип стойност", "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса", "verification": "Потвърждаване", + "verify_message": "Проверете съобщението", "verify_with_2fa": "Проверете с Cake 2FA", "version": "Версия ${currentVersion}", "view_all": "Виж всички", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 537695dd9..ef225041d 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Zpráva", + "message_verified": "Zpráva byla úspěšně ověřena", "methods": "Metody", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Zobrazit seed/klíče", "show_market_place": "Zobrazit trh", "show_seed": "Zobrazit seed", + "sign_message": "Podepsat zprávu", "sign_up": "Registrovat se", + "sign_verify_message": "Podepište nebo ověřte zprávu", + "sign_verify_message_sub": "Podepište nebo ověřte zprávu pomocí soukromého klíče", + "sign_verify_title": "Podepsat / ověřit", + "signature": "Podpis", + "signature_invalid_error": "Podpis není platný pro danou zprávu", "signTransaction": "Podepsat transakci", "signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.", "silent_payments": "Tiché platby", @@ -822,6 +829,7 @@ "value_type": "Typ hodnoty", "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován", "verification": "Ověření", + "verify_message": "Ověřit zprávu", "verify_with_2fa": "Ověřte pomocí Cake 2FA", "version": "Verze ${currentVersion}", "view_all": "Zobrazit vše", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 052015367..393c3d928 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Nachricht", + "message_verified": "Die Nachricht wurde erfolgreich überprüft", "methods": "Methoden", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Seed/Schlüssel anzeigen", "show_market_place": "Marktplatz anzeigen", "show_seed": "Seed zeigen", + "sign_message": "Nachricht unterschreiben", "sign_up": "Anmelden", + "sign_verify_message": "Nachricht unterschreiben oder überprüfen", + "sign_verify_message_sub": "Unterschreiben oder überprüfen Sie eine Nachricht mit Ihrem privaten Schlüssel", + "sign_verify_title": "Zeichen / überprüfen", + "signature": "Signatur", + "signature_invalid_error": "Die Signatur gilt nicht für die angegebene Nachricht", "signTransaction": "Transaktion unterzeichnen", "signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.", "silent_payments": "Stille Zahlungen", @@ -824,6 +831,7 @@ "value_type": "Werttyp", "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt", "verification": "Verifizierung", + "verify_message": "Nachricht überprüfen", "verify_with_2fa": "Verifizieren Sie mit Cake 2FA", "version": "Version ${currentVersion}", "view_all": "Alle anzeigen", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 0f0ebd470..4ac7dd8fd 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Message", + "message_verified": "The message was successfully verified", "methods": "Methods", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Show seed/keys", "show_market_place": "Show Marketplace", "show_seed": "Show seed", + "sign_message": "Sign Message", "sign_up": "Sign Up", + "sign_verify_message": "Sign or verify message", + "sign_verify_message_sub": "Sign or verify a message using your private key", + "sign_verify_title": "Sign / Verify", + "signature": "Signature", + "signature_invalid_error": "The signature is not valid for the message given", "signTransaction": "Sign Transaction", "signup_for_card_accept_terms": "Sign up for the card and accept the terms.", "silent_payments": "Silent Payments", @@ -823,6 +830,7 @@ "value_type": "Value Type", "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges", "verification": "Verification", + "verify_message": "Verify Message", "verify_with_2fa": "Verify with Cake 2FA", "version": "Version ${currentVersion}", "view_all": "View all", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 1e6eeae59..02d17ac96 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memorándum:", "message": "Mensaje", + "message_verified": "El mensaje fue verificado con éxito", "methods": "Métodos", "min_amount": "Mínimo: ${value}", "min_value": "Min: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Mostrar semilla/claves", "show_market_place": "Mostrar mercado", "show_seed": "Mostrar semilla", + "sign_message": "Mensaje de firma", "sign_up": "Registrarse", + "sign_verify_message": "Firmar o verificar el mensaje", + "sign_verify_message_sub": "Firmar o verificar un mensaje usando su clave privada", + "sign_verify_title": "Firmar / verificar", + "signature": "Firma", + "signature_invalid_error": "La firma no es válida para el mensaje dado", "signTransaction": "Firmar transacción", "signup_for_card_accept_terms": "Regístrese para obtener la tarjeta y acepte los términos.", "silent_payments": "Pagos silenciosos", @@ -823,6 +830,7 @@ "value_type": "Tipo de valor", "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados", "verification": "Verificación", + "verify_message": "Mensaje de verificación", "verify_with_2fa": "Verificar con Cake 2FA", "version": "Versión ${currentVersion}", "view_all": "Ver todo", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index a64a69514..4bc5c9809 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Mémo :", "message": "Message", + "message_verified": "Le message a été vérifié avec succès", "methods": "Méthodes", "min_amount": "Min : ${value}", "min_value": "Min: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Visualiser la phrase secrète (seed) et les clefs", "show_market_place": "Afficher la place de marché", "show_seed": "Visualiser la phrase secrète (seed)", + "sign_message": "Signer le message", "sign_up": "S'inscrire", + "sign_verify_message": "Signer ou vérifier le message", + "sign_verify_message_sub": "Signez ou vérifiez un message en utilisant votre clé privée", + "sign_verify_title": "Signe / vérifier", + "signature": "Signature", + "signature_invalid_error": "La signature n'est pas valable pour le message donné", "signTransaction": "Signer une transaction", "signup_for_card_accept_terms": "Inscrivez-vous pour la carte et acceptez les conditions.", "silent_payments": "Paiements silencieux", @@ -822,6 +829,7 @@ "value_type": "Type de valeur", "variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés", "verification": "Vérification", + "verify_message": "Vérifier le message", "verify_with_2fa": "Vérifier avec Cake 2FA", "version": "Version ${currentVersion}", "view_all": "Voir tout", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 219b3c939..025a33f6b 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Sako", + "message_verified": "An yi nasarar tabbatar da sakon", "methods": "Hanyoyin", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -663,7 +664,13 @@ "show_keys": "Nuna iri/maɓallai", "show_market_place": "Nuna dan kasuwa", "show_seed": "Nuna iri", + "sign_message": "Sa hannu", "sign_up": "Shiga", + "sign_verify_message": "Shiga ko Tabbatar da Saƙo", + "sign_verify_message_sub": "Shiga ko tabbatar da saƙo ta amfani da Maɓallinku na sirri", + "sign_verify_title": "Sa hannu / Tabbatar", + "signature": "Sa hannu", + "signature_invalid_error": "Sa hannu ba shi da inganci ga sakon da aka bayar", "signTransaction": "Sa hannu Ma'amala", "signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.", "silent_payments": "Biya silent", @@ -824,6 +831,7 @@ "value_type": "Nau'in darajar", "variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar", "verification": "tabbatar", + "verify_message": "Tabbatar saƙon", "verify_with_2fa": "Tabbatar da Cake 2FA", "version": "Sigar ${currentVersion}", "view_all": "Duba duka", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index b711939a4..346c420a9 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -370,6 +370,7 @@ "max_value": "मैक्स: ${value} ${currency}", "memo": "ज्ञापन:", "message": "संदेश", + "message_verified": "संदेश को सफलतापूर्वक सत्यापित किया गया था", "methods": "तरीकों", "min_amount": "न्यूनतम: ${value}", "min_value": "मिन: ${value} ${currency}", @@ -663,7 +664,13 @@ "show_keys": "बीज / कुंजियाँ दिखाएँ", "show_market_place": "बाज़ार दिखाएँ", "show_seed": "बीज दिखाओ", + "sign_message": "हस्ताक्षर संदेश", "sign_up": "साइन अप करें", + "sign_verify_message": "संदेश पर हस्ताक्षर या सत्यापित करें", + "sign_verify_message_sub": "अपनी निजी कुंजी का उपयोग करके किसी संदेश पर हस्ताक्षर या सत्यापित करें", + "sign_verify_title": "हस्ताक्षर / सत्यापित करें", + "signature": "हस्ताक्षर", + "signature_invalid_error": "हस्ताक्षर दिए गए संदेश के लिए मान्य नहीं है", "signTransaction": "लेन-देन पर हस्ताक्षर करें", "signup_for_card_accept_terms": "कार्ड के लिए साइन अप करें और शर्तें स्वीकार करें।", "silent_payments": "मूक भुगतान", @@ -824,6 +831,7 @@ "value_type": "मान प्रकार", "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है", "verification": "सत्यापन", + "verify_message": "संदेश सत्यापित करें", "verify_with_2fa": "केक 2FA के साथ सत्यापित करें", "version": "संस्करण ${currentVersion}", "view_all": "सभी देखें", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 401514735..6f5bc88a6 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -370,6 +370,7 @@ "max_value": "Maks.: ${value} ${currency}", "memo": "Memo:", "message": "Poruka", + "message_verified": "Poruka je uspješno provjerena", "methods": "Metode", "min_amount": "Minimalno: ${value}", "min_value": "Min.: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Prikaži pristupni izraz/ključ", "show_market_place": "Prikaži tržište", "show_seed": "Prikaži pristupni izraz", + "sign_message": "Poruka", "sign_up": "Prijavite se", + "sign_verify_message": "Potpisati ili provjeriti poruku", + "sign_verify_message_sub": "Potpišite ili provjerite poruku pomoću privatnog ključa", + "sign_verify_title": "Potpisati / provjeriti", + "signature": "Potpis", + "signature_invalid_error": "Potpis ne vrijedi za danu poruku", "signTransaction": "Potpišite transakciju", "signup_for_card_accept_terms": "Prijavite se za karticu i prihvatite uvjete.", "silent_payments": "Tiha plaćanja", @@ -822,6 +829,7 @@ "value_type": "Tipa vrijednosti", "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama", "verification": "Potvrda", + "verify_message": "Provjerite poruku", "verify_with_2fa": "Provjerite s Cake 2FA", "version": "Verzija ${currentVersion}", "view_all": "Prikaži sve", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index b6210b5dd..2bc298aa7 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Pesan", + "message_verified": "Pesan itu berhasil diverifikasi", "methods": "Metode", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -664,7 +665,13 @@ "show_keys": "Tampilkan seed/kunci", "show_market_place": "Tampilkan Pasar", "show_seed": "Tampilkan seed", + "sign_message": "Pesan tanda", "sign_up": "Daftar", + "sign_verify_message": "Tanda tangan atau verifikasi pesan", + "sign_verify_message_sub": "Menandatangani atau memverifikasi pesan menggunakan kunci pribadi Anda", + "sign_verify_title": "Tanda / verifikasi", + "signature": "Tanda tangan", + "signature_invalid_error": "Tanda tangan tidak valid untuk pesan yang diberikan", "signTransaction": "Tandatangani Transaksi", "signup_for_card_accept_terms": "Daftar untuk kartu dan terima syarat dan ketentuan.", "silent_payments": "Pembayaran diam", @@ -825,6 +832,7 @@ "value_type": "Jenis Nilai", "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih", "verification": "Verifikasi", + "verify_message": "Verifikasi pesan", "verify_with_2fa": "Verifikasi dengan Cake 2FA", "version": "Versi ${currentVersion}", "view_all": "Lihat Semua", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index fc4abf7c4..0548b0ad2 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -371,6 +371,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Messaggio", + "message_verified": "Il messaggio è stato verificato con successo", "methods": "Metodi", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -663,7 +664,13 @@ "show_keys": "Mostra seme/chiavi", "show_market_place": "Mostra mercato", "show_seed": "Mostra seme", + "sign_message": "Messaggio di firma", "sign_up": "Registrati", + "sign_verify_message": "Firmare o verificare il messaggio", + "sign_verify_message_sub": "Firma o verifica un messaggio utilizzando la chiave privata", + "sign_verify_title": "Firmare / verificare", + "signature": "Firma", + "signature_invalid_error": "La firma non è valida per il messaggio dato", "signTransaction": "Firma la transazione", "signup_for_card_accept_terms": "Registrati per la carta e accetta i termini.", "silent_payments": "Pagamenti silenziosi", @@ -824,6 +831,7 @@ "value_type": "Tipo di valore", "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati", "verification": "Verifica", + "verify_message": "Verificare il messaggio", "verify_with_2fa": "Verifica con Cake 2FA", "version": "Versione ${currentVersion}", "view_all": "Visualizza tutto", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 98495fc8b..c53a6d001 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -371,6 +371,7 @@ "max_value": "マックス: ${value} ${currency}", "memo": "メモ:", "message": "メッセージ", + "message_verified": "メッセージは正常に検証されました", "methods": "メソッド", "min_amount": "最小: ${value}", "min_value": "分: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "シード/キーを表示する", "show_market_place": "マーケットプレイスを表示", "show_seed": "シードを表示", + "sign_message": "署名メッセージ", "sign_up": "サインアップ", + "sign_verify_message": "メッセージに署名または確認します", + "sign_verify_message_sub": "秘密鍵を使用してメッセージに署名または確認します", + "sign_verify_title": "署名 /検証", + "signature": "サイン", + "signature_invalid_error": "署名は、指定されたメッセージに対して無効です", "signTransaction": "トランザクションに署名する", "signup_for_card_accept_terms": "カードにサインアップして、利用規約に同意してください。", "silent_payments": "サイレント支払い", @@ -823,6 +830,7 @@ "value_type": "値タイプ", "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません", "verification": "検証", + "verify_message": "メッセージを確認します", "verify_with_2fa": "Cake 2FA で検証する", "version": "バージョン ${currentVersion}", "view_all": "すべて表示", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 60c52b21f..be6757d99 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -370,6 +370,7 @@ "max_value": "맥스: ${value} ${currency}", "memo": "메모:", "message": "메시지", + "message_verified": "메시지가 성공적으로 확인되었습니다", "methods": "행동 양식", "min_amount": "최소: ${value}", "min_value": "최소: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "시드 / 키 표시", "show_market_place": "마켓플레이스 표시", "show_seed": "종자 표시", + "sign_message": "서명 메시지", "sign_up": "가입", + "sign_verify_message": "메시지에 서명하거나 확인하십시오", + "sign_verify_message_sub": "개인 키를 사용하여 메시지에 서명하거나 확인하십시오", + "sign_verify_title": "서명 / 확인", + "signature": "서명", + "signature_invalid_error": "서명은 주어진 메시지에 유효하지 않습니다", "signTransaction": "거래 서명", "signup_for_card_accept_terms": "카드에 가입하고 약관에 동의합니다.", "silent_payments": "조용한 지불", @@ -823,6 +830,7 @@ "value_type": "가치 유형", "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.", "verification": "검증", + "verify_message": "메시지를 확인하십시오", "verify_with_2fa": "케이크 2FA로 확인", "version": "버전 ${currentVersion}", "view_all": "모두 보기", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 42643be48..c53dffb6b 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -370,6 +370,7 @@ "max_value": "အများဆုံး- ${value} ${currency}", "memo": "မှတ်စုတို:", "message": "မက်ဆေ့ချ်", + "message_verified": "မက်ဆေ့ခ်ျကိုအောင်မြင်စွာအတည်ပြုခဲ့သည်", "methods": "နည်းလမ်းများ", "min_amount": "အနည်းဆုံး- ${value}", "min_value": "အနည်းဆုံး- ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "မျိုးစေ့ /သော့များကို ပြပါ။", "show_market_place": "စျေးကွက်ကိုပြသပါ။", "show_seed": "မျိုးစေ့ကိုပြပါ။", + "sign_message": "လက်မှတ်စာ", "sign_up": "ဆိုင်းအပ်", + "sign_verify_message": "မက်ဆေ့ခ်ျကိုလက်မှတ်ထိုးသို့မဟုတ်အတည်ပြုရန်", + "sign_verify_message_sub": "သင်၏ကိုယ်ပိုင်သော့ကို သုံး. မက်ဆေ့ခ်ျကိုလက်မှတ်ထိုးပါ", + "sign_verify_title": "လက်မှတ်ထိုး / အတည်ပြုရန်", + "signature": "လက်မှတ်", + "signature_invalid_error": "အဆိုပါလက်မှတ်ပေးထားသောမက်ဆေ့ခ်ျကိုများအတွက်မမှန်ကန်ပါ", "signTransaction": "ငွေလွှဲဝင်ပါ။", "signup_for_card_accept_terms": "ကတ်အတွက် စာရင်းသွင်းပြီး စည်းကမ်းချက်များကို လက်ခံပါ။", "silent_payments": "အသံတိတ်ငွေပေးချေမှု", @@ -822,6 +829,7 @@ "value_type": "Value အမျိုးအစား", "variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။", "verification": "စိစစ်ခြင်း။", + "verify_message": "မက်ဆေ့ခ်ျကိုအတည်ပြုရန်", "verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။", "version": "ဗားရှင်း ${currentVersion}", "view_all": "အားလုံးကိုကြည့်ရှုပါ။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 0f6149182..2d55344f5 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Bericht", + "message_verified": "Het bericht is succesvol geverifieerd", "methods": "Methoden", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Toon zaad/sleutels", "show_market_place": "Toon Marktplaats", "show_seed": "Toon zaad", + "sign_message": "Aanmeldingsbericht", "sign_up": "Aanmelden", + "sign_verify_message": "Teken of verifieer bericht", + "sign_verify_message_sub": "Teken of verifieer een bericht met uw privésleutel", + "sign_verify_title": "Ondertekenen / verifiëren", + "signature": "Handtekening", + "signature_invalid_error": "De handtekening is niet geldig voor het gegeven bericht", "signTransaction": "Transactie ondertekenen", "signup_for_card_accept_terms": "Meld je aan voor de kaart en accepteer de voorwaarden.", "silent_payments": "Stille betalingen", @@ -822,6 +829,7 @@ "value_type": "Waarde type", "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen", "verification": "Verificatie", + "verify_message": "Verifieer bericht", "verify_with_2fa": "Controleer met Cake 2FA", "version": "Versie ${currentVersion}", "view_all": "Alles bekijken", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 48d6e38f6..833fc0308 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Notatka:", "message": "Wiadomość", + "message_verified": "Wiadomość została pomyślnie zweryfikowana", "methods": "Metody", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Pokaż seed/klucze", "show_market_place": "Pokaż rynek", "show_seed": "Pokaż frazy seed", + "sign_message": "Podpisuj wiadomość", "sign_up": "Zarejestruj się", + "sign_verify_message": "Podpisz lub zweryfikuj wiadomość", + "sign_verify_message_sub": "Podpisz lub zweryfikuj wiadomość za pomocą klucza prywatnego", + "sign_verify_title": "Podpisać / weryfikować", + "signature": "Podpis", + "signature_invalid_error": "Podpis nie jest ważny dla podanej wiadomości", "signTransaction": "Podpisz transakcję", "signup_for_card_accept_terms": "Zarejestruj się, aby otrzymać kartę i zaakceptuj warunki.", "silent_payments": "Ciche płatności", @@ -822,6 +829,7 @@ "value_type": "Typ wartości", "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach", "verification": "Weryfikacja", + "verify_message": "Sprawdź wiadomość", "verify_with_2fa": "Sprawdź za pomocą Cake 2FA", "version": "Wersja ${currentVersion}", "view_all": "Wyświetl wszystko", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 070f3f776..bd6d9b506 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -371,6 +371,7 @@ "max_value": "Máx: ${value} ${currency}", "memo": "Memorando:", "message": "Mensagem", + "message_verified": "A mensagem foi verificada com sucesso", "methods": "Métodos", "min_amount": "Mínimo: ${valor}", "min_value": "Mín: ${value} ${currency}", @@ -663,7 +664,13 @@ "show_keys": "Mostrar semente/chaves", "show_market_place": "Mostrar mercado", "show_seed": "Mostrar semente", + "sign_message": "Mensagem de assinar", "sign_up": "Inscrever-se", + "sign_verify_message": "Assinar ou verificar mensagem", + "sign_verify_message_sub": "Assine ou verifique uma mensagem usando sua chave privada", + "sign_verify_title": "Assinar / verificar", + "signature": "Assinatura", + "signature_invalid_error": "A assinatura não é válida para a mensagem dada", "signTransaction": "Assinar transação", "signup_for_card_accept_terms": "Cadastre-se no cartão e aceite os termos.", "silent_payments": "Pagamentos silenciosos", @@ -824,6 +831,7 @@ "value_type": "Tipo de valor", "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas", "verification": "Verificação", + "verify_message": "Verifique a mensagem", "verify_with_2fa": "Verificar com Cake 2FA", "version": "Versão ${currentVersion}", "view_all": "Ver todos", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 695877c77..d43572351 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -370,6 +370,7 @@ "max_value": "Макс: ${value} ${currency}", "memo": "Памятка:", "message": "Сообщение", + "message_verified": "Сообщение было успешно проверено", "methods": "Методы", "min_amount": "Минимум: ${value}", "min_value": "Мин: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Показать мнемоническую фразу/ключи", "show_market_place": "Показать торговую площадку", "show_seed": "Показать мнемоническую фразу", + "sign_message": "Сообщение о знаке", "sign_up": "Зарегистрироваться", + "sign_verify_message": "Подписать или проверить сообщение", + "sign_verify_message_sub": "Подписать или проверить сообщение, используя свой закрытый ключ", + "sign_verify_title": "Знак / проверка", + "signature": "Подпись", + "signature_invalid_error": "Подпись недопустима для данного сообщения", "signTransaction": "Подписать транзакцию", "signup_for_card_accept_terms": "Подпишитесь на карту и примите условия.", "silent_payments": "Молчаливые платежи", @@ -823,6 +830,7 @@ "value_type": "Тип значения", "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.", "verification": "Проверка", + "verify_message": "Проверьте сообщение", "verify_with_2fa": "Подтвердить с помощью Cake 2FA", "version": "Версия ${currentVersion}", "view_all": "Просмотреть все", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 5757eed0b..d948ba6d6 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -370,6 +370,7 @@ "max_value": "ขั้นสูง: ${value} ${currency}", "memo": "หมายเหตุ:", "message": "ข้อความ", + "message_verified": "ข้อความได้รับการตรวจสอบอย่างประสบความสำเร็จ", "methods": "วิธีการ", "min_amount": "จำนวนขั้นต่ำ: ${value}", "min_value": "ขั้นต่ำ: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "แสดงซีด/คีย์", "show_market_place": "แสดงตลาดกลาง", "show_seed": "แสดงซีด", + "sign_message": "ลงนามข้อความ", "sign_up": "สมัครสมาชิก", + "sign_verify_message": "ลงชื่อเข้าใช้หรือตรวจสอบข้อความ", + "sign_verify_message_sub": "ลงชื่อเข้าใช้หรือตรวจสอบข้อความโดยใช้คีย์ส่วนตัวของคุณ", + "sign_verify_title": "ลงชื่อ / ตรวจสอบ", + "signature": "ลายเซ็น", + "signature_invalid_error": "ลายเซ็นไม่ถูกต้องสำหรับข้อความที่ให้ไว้", "signTransaction": "ลงนามในการทำธุรกรรม", "signup_for_card_accept_terms": "ลงทะเบียนสำหรับบัตรและยอมรับเงื่อนไข", "silent_payments": "การชำระเงินเงียบ", @@ -822,6 +829,7 @@ "value_type": "ประเภทค่า", "variable_pair_not_supported": "คู่ความสัมพันธ์ที่เปลี่ยนแปลงได้นี้ไม่สนับสนุนกับหุ้นที่เลือก", "verification": "การตรวจสอบ", + "verify_message": "ยืนยันข้อความ", "verify_with_2fa": "ตรวจสอบกับ Cake 2FA", "version": "เวอร์ชัน ${currentVersion}", "view_all": "ดูทั้งหมด", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 7fc83afd8..a0ab030c8 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -370,6 +370,7 @@ "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Mensahe", + "message_verified": "Ang mensahe ay matagumpay na na -verify", "methods": "Mga Paraan", "min_amount": "Min: ${value}", "min_value": "Min: ${value} ${currency}", @@ -660,6 +661,12 @@ "show_details": "Ipakita ang mga detalye", "show_keys": "Ipakita ang mga seed/key", "show_market_place": "Ipakita ang Marketplace", + "sign_message": "Mag -sign Message", + "sign_verify_message": "Mag -sign o i -verify ang mensahe", + "sign_verify_message_sub": "Mag -sign o i -verify ang isang mensahe gamit ang iyong pribadong key", + "sign_verify_title": "Mag -sign / Mag -verify", + "signature": "Lagda", + "signature_invalid_error": "Ang lagda ay hindi wasto para sa ibinigay na mensahe", "show_seed": "Ipakita ang seed", "sign_up": "Mag-sign Up", "signTransaction": "Mag-sign ang Transaksyon", @@ -820,6 +827,7 @@ "use_testnet": "Gumamit ng testnet", "value": "Halaga", "value_type": "Uri ng halaga", + "verify_message": "I -verify ang mensahe", "variable_pair_not_supported": "Ang variable na pares na ito ay hindi suportado sa mga napiling exchange", "verification": "Pag-verify", "verify_with_2fa": "Mag-verify sa Cake 2FA", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 4d1aa43e4..e7cdc5b12 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -370,6 +370,7 @@ "max_value": "En fazla: ${value} ${currency}", "memo": "Memo:", "message": "İleti", + "message_verified": "Mesaj başarıyla doğrulandı", "methods": "Yöntemler", "min_amount": "Min: ${value}", "min_value": "En az: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "Tohumları/anahtarları göster", "show_market_place": "Pazar Yerini Göster", "show_seed": "Tohumları göster", + "sign_message": "İşaret mesajı", "sign_up": "Kaydol", + "sign_verify_message": "Mesajı işaretleyin veya doğrulayın", + "sign_verify_message_sub": "Özel anahtarınızı kullanarak bir mesajı imzalayın veya doğrulayın", + "sign_verify_title": "İşaretle / Doğrula", + "signature": "İmza", + "signature_invalid_error": "İmza verilen mesaj için geçerli değil", "signTransaction": "İşlem İmzala", "signup_for_card_accept_terms": "Kart için kaydol ve koşulları kabul et.", "silent_payments": "Sessiz ödemeler", @@ -822,6 +829,7 @@ "value_type": "Değer türü", "variable_pair_not_supported": "Bu değişken paritesi seçilen borsalarda desteklenmemekte", "verification": "Doğrulama", + "verify_message": "Mesajı Doğrula", "verify_with_2fa": "Cake 2FA ile Doğrulayın", "version": "Sürüm ${currentVersion}", "view_all": "Hepsini göster", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 22edec0d5..91b5b5266 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -370,6 +370,7 @@ "max_value": "Макс: ${value} ${currency}", "memo": "Пам’ятка:", "message": "повідомлення", + "message_verified": "Повідомлення було успішно перевірено", "methods": "методи", "min_amount": "Мінімум: ${value}", "min_value": "Мін: ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Показати мнемонічну фразу/ключі", "show_market_place": "Відображати маркетплейс", "show_seed": "Показати мнемонічну фразу", + "sign_message": "Підпишіть повідомлення", "sign_up": "Зареєструватися", + "sign_verify_message": "Підпишіть або перевірити повідомлення", + "sign_verify_message_sub": "Підпишіть або перевірте повідомлення за допомогою вашого приватного ключа", + "sign_verify_title": "Знак / Перевірка", + "signature": "Підпис", + "signature_invalid_error": "Підпис не є дійсним для наведеного повідомлення", "signTransaction": "Підписати транзакцію", "signup_for_card_accept_terms": "Зареєструйтеся на картку та прийміть умови.", "silent_payments": "Мовчазні платежі", @@ -823,6 +830,7 @@ "value_type": "Тип значення", "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами", "verification": "Перевірка", + "verify_message": "Перевірте повідомлення", "verify_with_2fa": "Перевірте за допомогою Cake 2FA", "version": "Версія ${currentVersion}", "view_all": "Переглянути все", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 590f344d8..e54a0db34 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -370,6 +370,7 @@ "max_value": "زیادہ سے زیادہ: ${value} ${currency}", "memo": "میمو:", "message": "ﻡﺎﻐﯿﭘ", + "message_verified": "پیغام کی کامیابی کے ساتھ تصدیق کی گئی", "methods": "ﮯﻘﯾﺮﻃ", "min_amount": "کم سے کم: ${value}", "min_value": "کم سے کم: ${value} ${currency}", @@ -663,7 +664,13 @@ "show_keys": "بیج / چابیاں دکھائیں۔", "show_market_place": "بازار دکھائیں۔", "show_seed": "بیج دکھائیں۔", + "sign_message": "سائن پیغام", "sign_up": "سائن اپ", + "sign_verify_message": "پیغام پر دستخط کریں یا تصدیق کریں", + "sign_verify_message_sub": "اپنی نجی کلید کا استعمال کرتے ہوئے کسی پیغام پر دستخط کریں یا اس کی تصدیق کریں", + "sign_verify_title": "سائن / تصدیق کریں", + "signature": "دستخط", + "signature_invalid_error": "دستخط دیئے گئے پیغام کے لئے درست نہیں ہے", "signTransaction": "۔ﮟﯾﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ", "signup_for_card_accept_terms": "کارڈ کے لیے سائن اپ کریں اور شرائط کو قبول کریں۔", "silent_payments": "خاموش ادائیگی", @@ -824,6 +831,7 @@ "value_type": "قدر کی قسم", "variable_pair_not_supported": "یہ متغیر جوڑا منتخب ایکسچینجز کے ساتھ تعاون یافتہ نہیں ہے۔", "verification": "تصدیق", + "verify_message": "پیغام کی تصدیق کریں", "verify_with_2fa": "کیک 2FA سے تصدیق کریں۔", "version": "ورژن ${currentVersion}", "view_all": "سب دیکھیں", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index e5cf3d3f9..8f47d8543 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -371,6 +371,7 @@ "max_value": "kò gbọ́dọ̀ tóbi ju ${value} ${currency}", "memo": "Àkọsílẹ̀:", "message": "Ifiranṣẹ", + "message_verified": "Ifiranṣẹ naa ni aṣeyọri ni ifijišẹ", "methods": "Awọn ọna", "min_amount": "kò kéré ju: ${value}", "min_value": "kò gbọ́dọ̀ kéré ju ${value} ${currency}", @@ -662,7 +663,13 @@ "show_keys": "Wo hóró / àwọn kọ́kọ́rọ́", "show_market_place": "Wa Sopọ Pataki", "show_seed": "Wo hóró", + "sign_message": "Ifiranṣẹ Ami", "sign_up": "Forúkọ sílẹ̀", + "sign_verify_message": "Ami tabi ṣayẹwo ifiranṣẹ", + "sign_verify_message_sub": "Wọle tabi ṣayẹwo ifiranṣẹ kan nipa lilo bọtini ikọkọ rẹ", + "sign_verify_title": "Ami / Daju", + "signature": "Ibọwọlu", + "signature_invalid_error": "Ibuwọlu ko wulo fun ifiranṣẹ ti a fun", "signTransaction": "Wole Idunadura", "signup_for_card_accept_terms": "Ẹ f'orúkọ sílẹ̀ láti gba káàdì àti àjọrò.", "silent_payments": "Awọn sisanwo ipalọlọ", @@ -823,6 +830,7 @@ "value_type": "Iru iye", "variable_pair_not_supported": "A kì í ṣe k'á fi àwọn ilé pàṣípààrọ̀ yìí ṣe pàṣípààrọ̀ irú owó méji yìí", "verification": "Ìjẹ́rìísí", + "verify_message": "Daju ifiranṣẹ", "verify_with_2fa": "Ṣeẹda pẹlu Cake 2FA", "version": "Àtúnse ${currentVersion}", "view_all": "Wo gbogbo nǹkan kan", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 25024d0ed..c864a529b 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -370,6 +370,7 @@ "max_value": "最大: ${value} ${currency}", "memo": "备忘录:", "message": "信息", + "message_verified": "该消息已成功验证", "methods": "方法", "min_amount": "最小值: ${value}", "min_value": "最小: ${value} ${currency}", @@ -661,7 +662,13 @@ "show_keys": "显示种子/密钥", "show_market_place": "显示市场", "show_seed": "显示种子", + "sign_message": "标志消息", "sign_up": "注册", + "sign_verify_message": "签名或验证消息", + "sign_verify_message_sub": "使用您的私钥签名或验证消息", + "sign_verify_title": "签名 /验证", + "signature": "签名", + "signature_invalid_error": "签名对于给出的消息无效", "signTransaction": "签署交易", "signup_for_card_accept_terms": "注册卡并接受条款。", "silent_payments": "无声付款", @@ -822,6 +829,7 @@ "value_type": "值类型", "variable_pair_not_supported": "所选交易所不支持此变量对", "verification": "验证", + "verify_message": "验证消息", "verify_with_2fa": "用 Cake 2FA 验证", "version": "版本 ${currentVersion}", "view_all": "查看全部", From 7c9b72483a66e113db6fee8c23d3b8616c76c41f Mon Sep 17 00:00:00 2001 From: Matthew Fosse <matt@fosse.co> Date: Sat, 17 Aug 2024 19:28:45 -0400 Subject: [PATCH 05/10] Socket null handling (#1610) * return null if in connection failure state * reconnect on connection failure * better connection handling * probably not necessary but just incase * connection handling updates * add cancelOnError: true --- cw_bitcoin/lib/electrum.dart | 54 +++++++++++++++++------------ cw_bitcoin/lib/electrum_wallet.dart | 22 +++++------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index 69b07d7c1..28043d0c0 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -66,6 +66,7 @@ class ElectrumClient { try { await socket?.close(); + socket = null; } catch (_) {} try { @@ -90,33 +91,40 @@ class ElectrumClient { } _setConnectionStatus(ConnectionStatus.connected); - socket!.listen((Uint8List event) { - try { - final msg = utf8.decode(event.toList()); - final messagesList = msg.split("\n"); - for (var message in messagesList) { - if (message.isEmpty) { - continue; + socket!.listen( + (Uint8List event) { + try { + final msg = utf8.decode(event.toList()); + final messagesList = msg.split("\n"); + for (var message in messagesList) { + if (message.isEmpty) { + continue; + } + _parseResponse(message); } - _parseResponse(message); + } catch (e) { + print(e.toString()); } - } catch (e) { - print(e.toString()); - } - }, onError: (Object error) { - final errorMsg = error.toString(); - print(errorMsg); - unterminatedString = ''; + }, + onError: (Object error) { + socket = null; + final errorMsg = error.toString(); + print(errorMsg); + unterminatedString = ''; - final currentHost = socket?.address.host; - final isErrorForCurrentHost = errorMsg.contains(" ${currentHost} "); + final currentHost = socket?.address.host; + final isErrorForCurrentHost = errorMsg.contains(" ${currentHost} "); - if (currentHost != null && isErrorForCurrentHost) - _setConnectionStatus(ConnectionStatus.failed); - }, onDone: () { - unterminatedString = ''; - if (host == socket?.address.host) _setConnectionStatus(ConnectionStatus.disconnected); - }); + if (currentHost != null && isErrorForCurrentHost) + _setConnectionStatus(ConnectionStatus.failed); + }, + onDone: () { + socket = null; + unterminatedString = ''; + if (host == socket?.address.host) _setConnectionStatus(ConnectionStatus.disconnected); + }, + cancelOnError: true, + ); keepAlive(); } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 8f2360f26..b8d9adb14 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -218,10 +218,7 @@ abstract class ElectrumWalletBase if (electrumClient.isConnected) { syncStatus = SyncedSyncStatus(); } else { - if (electrumClient.uri != null) { - await electrumClient.connectToUri(electrumClient.uri!, useSSL: electrumClient.useSSL); - startSync(); - } + syncStatus = NotConnectedSyncStatus(); } } } @@ -265,6 +262,7 @@ abstract class ElectrumWalletBase Future<Isolate>? _isolate; void Function(FlutterErrorDetails)? _onError; + Timer? _reconnectTimer; Timer? _autoSaveTimer; static const int _autoSaveInterval = 30; @@ -1980,13 +1978,6 @@ abstract class ElectrumWalletBase break; case ConnectionStatus.failed: syncStatus = LostConnectionSyncStatus(); - // wait for 5 seconds and then try to reconnect: - Future.delayed(Duration(seconds: 5), () { - electrumClient.connectToUri( - node!.uri, - useSSL: node!.useSSL ?? false, - ); - }); break; case ConnectionStatus.connecting: syncStatus = ConnectingSyncStatus(); @@ -1996,7 +1987,11 @@ abstract class ElectrumWalletBase } void _syncStatusReaction(SyncStatus syncStatus) async { - if (syncStatus is NotConnectedSyncStatus) { + if (syncStatus is SyncingSyncStatus) { + return; + } + + if (syncStatus is NotConnectedSyncStatus || syncStatus is LostConnectionSyncStatus) { // Needs to re-subscribe to all scripthashes when reconnected _scripthashesUpdateSubject = {}; @@ -2004,7 +1999,8 @@ abstract class ElectrumWalletBase _isTryingToConnect = true; - Future.delayed(Duration(seconds: 10), () { + _reconnectTimer?.cancel(); + _reconnectTimer = Timer(Duration(seconds: 10), () { if (this.syncStatus is! SyncedSyncStatus && this.syncStatus is! SyncedTipSyncStatus) { this.electrumClient.connectToUri( node!.uri, From c59d39d42d4a8a27208ea3bad5144781801823a5 Mon Sep 17 00:00:00 2001 From: Omar Hatem <omarh.ismail1@gmail.com> Date: Sun, 18 Aug 2024 03:37:15 +0300 Subject: [PATCH 06/10] Generic fixes (#1619) * update fee rates * periodically update fees * minor enhancements * minor enhancements * some improvements add solana node * handle empty hex as null * minor improvement * fix imports * fix app hanging on splash screen * update app versions temporarily disable sign/verify for hardware wallets --- assets/solana_node_list.yml | 3 +++ assets/text/Monerocom_Release_Notes.txt | 5 ++--- assets/text/Release_Notes.txt | 7 ++----- cw_bitcoin/lib/electrum_wallet.dart | 12 +++++++++--- cw_evm/lib/evm_chain_wallet.dart | 5 ++++- cw_monero/lib/monero_wallet_service.dart | 6 +++--- cw_monero/pubspec.lock | 15 +++++++-------- cw_monero/pubspec.yaml | 5 +---- cw_wownero/pubspec.lock | 19 +++++++++---------- cw_wownero/pubspec.yaml | 5 +---- lib/core/wallet_loading_service.dart | 8 ++++++-- lib/reactions/bootstrap.dart | 2 +- .../on_authentication_state_change.dart | 17 ++++------------- .../screens/dashboard/pages/balance_page.dart | 4 ++-- .../dashboard/dashboard_view_model.dart | 4 +++- .../exchange/exchange_view_model.dart | 9 +++++++++ macos/Podfile.lock | 18 ++++++------------ pubspec_base.yaml | 7 ++----- scripts/android/app_env.sh | 8 ++++---- scripts/ios/app_env.sh | 8 ++++---- scripts/linux/app_env.sh | 4 ++-- scripts/macos/app_env.sh | 8 ++++---- scripts/windows/build_exe_installer.iss | 2 +- 23 files changed, 89 insertions(+), 92 deletions(-) diff --git a/assets/solana_node_list.yml b/assets/solana_node_list.yml index 4a2e12161..e3ff9138e 100644 --- a/assets/solana_node_list.yml +++ b/assets/solana_node_list.yml @@ -1,4 +1,7 @@ - uri: rpc.ankr.com is_default: true + useSSL: true +- + uri: api.mainnet-beta.solana.com:443 useSSL: true \ No newline at end of file diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt index c90d54524..11a3ad803 100644 --- a/assets/text/Monerocom_Release_Notes.txt +++ b/assets/text/Monerocom_Release_Notes.txt @@ -1,4 +1,3 @@ -Monero synchronization improvements -Enhance error handling -UI enhancements +Scan and verify messages +Synchronization enhancements Bug fixes \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index 34bca2e5e..11a3ad803 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,6 +1,3 @@ -Wallets enhancements -Monero synchronization improvements -Improve wallet backups -Enhance error handling -UI enhancements +Scan and verify messages +Synchronization enhancements Bug fixes \ No newline at end of file diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index b8d9adb14..2d0b989d7 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -264,7 +264,8 @@ abstract class ElectrumWalletBase void Function(FlutterErrorDetails)? _onError; Timer? _reconnectTimer; Timer? _autoSaveTimer; - static const int _autoSaveInterval = 30; + Timer? _updateFeeRateTimer; + static const int _autoSaveInterval = 1; Future<void> init() async { await walletAddresses.init(); @@ -272,7 +273,7 @@ abstract class ElectrumWalletBase await save(); _autoSaveTimer = - Timer.periodic(Duration(seconds: _autoSaveInterval), (_) async => await save()); + Timer.periodic(Duration(minutes: _autoSaveInterval), (_) async => await save()); } @action @@ -425,6 +426,10 @@ abstract class ElectrumWalletBase await updateTransactions(); await updateAllUnspents(); await updateBalance(); + updateFeeRates(); + + _updateFeeRateTimer ??= + Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates()); if (alwaysScan == true) { _setListeners(walletInfo.restoreHeight); @@ -1213,6 +1218,7 @@ abstract class ElectrumWalletBase await electrumClient.close(); } catch (_) {} _autoSaveTimer?.cancel(); + _updateFeeRateTimer?.cancel(); } @action @@ -1371,7 +1377,7 @@ abstract class ElectrumWalletBase if (confirmations > 0) return false; - if (transactionHex == null) { + if (transactionHex == null || transactionHex.isEmpty) { return false; } diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index bbf972f0d..0ade2215e 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -113,6 +113,8 @@ abstract class EVMChainWalletBase int? gasBaseFee = 0; int estimatedGasUnits = 0; + Timer? _updateFeesTimer; + bool _isTransactionUpdating; // TODO: remove after integrating our own node and having eth_newPendingTransactionFilter @@ -263,6 +265,7 @@ abstract class EVMChainWalletBase void close() { _client.stop(); _transactionsUpdateTimer?.cancel(); + _updateFeesTimer?.cancel(); } @action @@ -297,7 +300,7 @@ abstract class EVMChainWalletBase await _updateEstimatedGasFeeParams(); - Timer.periodic(const Duration(seconds: 10), (timer) async { + _updateFeesTimer ??= Timer.periodic(const Duration(seconds: 30), (timer) async { await _updateEstimatedGasFeeParams(); }); diff --git a/cw_monero/lib/monero_wallet_service.dart b/cw_monero/lib/monero_wallet_service.dart index d771d1815..f9973f430 100644 --- a/cw_monero/lib/monero_wallet_service.dart +++ b/cw_monero/lib/monero_wallet_service.dart @@ -119,7 +119,7 @@ class MoneroWalletService extends WalletService< } @override - Future<MoneroWallet> openWallet(String name, String password) async { + Future<MoneroWallet> openWallet(String name, String password, {bool? retryOnFailure}) async { MoneroWallet? wallet; try { final path = await pathForWallet(name: name, type: getType()); @@ -181,12 +181,12 @@ class MoneroWalletService extends WalletService< wallet.onError != null) { wallet.onError!(FlutterErrorDetails(exception: e, stack: s)); } - if (invalidPassword) { + if (invalidPassword || retryOnFailure == false) { rethrow; } await restoreOrResetWalletFiles(name); - return openWallet(name, password); + return openWallet(name, password, retryOnFailure: false); } } diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 51efd4076..13c70cfad 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -295,10 +295,10 @@ packages: dependency: transitive description: name: hashlib - sha256: "5037d3b8c36384c03a728543ae67d962a56970c5432a50862279fe68ee4c8411" + sha256: d41795742c10947930630118c6836608deeb9047cd05aee32d2baeb697afd66a url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.19.2" hashlib_codecs: dependency: transitive description: @@ -575,12 +575,11 @@ packages: polyseed: dependency: "direct main" description: - path: "." - ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f - resolved-ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f - url: "https://github.com/mrcyjanek/polyseed_dart" - source: git - version: "0.0.5" + name: polyseed + sha256: "11d4dbee409db053c5e9cd77382b2f5115f43fc2529158a826a96f3ba505d770" + url: "https://pub.dev" + source: hosted + version: "0.0.6" pool: dependency: transitive description: diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index 7f5da2621..3053977de 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -19,10 +19,7 @@ dependencies: flutter_mobx: ^2.0.6+1 intl: ^0.18.0 encrypt: ^5.0.1 - polyseed: - git: - url: https://github.com/mrcyjanek/polyseed_dart - ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + polyseed: ^0.0.6 cw_core: path: ../cw_core monero: diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index f164b3086..58831085f 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -295,18 +295,18 @@ packages: dependency: transitive description: name: hashlib - sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96" + sha256: d41795742c10947930630118c6836608deeb9047cd05aee32d2baeb697afd66a url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.19.2" hashlib_codecs: dependency: transitive description: name: hashlib_codecs - sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626" + sha256: "2b570061f5a4b378425be28a576c1e11783450355ad4345a19f606ff3d96db0f" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.5.0" hive: dependency: transitive description: @@ -567,12 +567,11 @@ packages: polyseed: dependency: "direct main" description: - path: "." - ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f - resolved-ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f - url: "https://github.com/mrcyjanek/polyseed_dart" - source: git - version: "0.0.5" + name: polyseed + sha256: "11d4dbee409db053c5e9cd77382b2f5115f43fc2529158a826a96f3ba505d770" + url: "https://pub.dev" + source: hosted + version: "0.0.6" pool: dependency: transitive description: diff --git a/cw_wownero/pubspec.yaml b/cw_wownero/pubspec.yaml index eb14286a9..b9306711d 100644 --- a/cw_wownero/pubspec.yaml +++ b/cw_wownero/pubspec.yaml @@ -19,10 +19,7 @@ dependencies: flutter_mobx: ^2.0.6+1 intl: ^0.18.0 encrypt: ^5.0.1 - polyseed: - git: - url: https://github.com/mrcyjanek/polyseed_dart - ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + polyseed: ^0.0.6 cw_core: path: ../cw_core monero: diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart index 2b570f14c..0087b1332 100644 --- a/lib/core/wallet_loading_service.dart +++ b/lib/core/wallet_loading_service.dart @@ -60,7 +60,9 @@ class WalletLoadingService { String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):"; try { corruptedWalletsSeeds += await _getCorruptedWalletSeeds(name, type); - } catch (_) {} + } catch (e) { + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; + } // try opening another wallet that is not corrupted to give user access to the app final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName); @@ -90,7 +92,9 @@ class WalletLoadingService { if (!corruptedWalletsSeeds.contains(seeds)) { corruptedWalletsSeeds += seeds; } - } catch (_) {} + } catch (e) { + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; + } } } diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index 5b1a0ace7..bf045c0dd 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -27,7 +27,7 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async { authenticationStore.installed(); } - await startAuthenticationStateChange(authenticationStore, navigatorKey); + startAuthenticationStateChange(authenticationStore, navigatorKey); startCurrentWalletChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore); diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index 014306b98..1aa0a12c6 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -7,26 +7,17 @@ import 'package:flutter/widgets.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/entities/load_current_wallet.dart'; import 'package:cake_wallet/store/authentication_store.dart'; +import 'package:rxdart/subjects.dart'; ReactionDisposer? _onAuthenticationStateChange; dynamic loginError; -StreamController<dynamic> authenticatedErrorStreamController = StreamController<dynamic>(); +StreamController<dynamic> authenticatedErrorStreamController = BehaviorSubject<dynamic>(); -Future<void> reInitializeStreamController() async { - if (!authenticatedErrorStreamController.isClosed) { - await authenticatedErrorStreamController.close(); - } - - authenticatedErrorStreamController = StreamController<dynamic>(); -} - -Future<void> startAuthenticationStateChange( +void startAuthenticationStateChange( AuthenticationStore authenticationStore, GlobalKey<NavigatorState> navigatorKey, -) async { - await reInitializeStreamController(); - +) { authenticatedErrorStreamController.stream.listen((event) { if (authenticationStore.state == AuthenticationState.allowed) { ExceptionHandler.showError(event.toString(), delayInSeconds: 3); diff --git a/lib/src/screens/dashboard/pages/balance_page.dart b/lib/src/screens/dashboard/pages/balance_page.dart index 770cda6f9..57f908986 100644 --- a/lib/src/screens/dashboard/pages/balance_page.dart +++ b/lib/src/screens/dashboard/pages/balance_page.dart @@ -287,8 +287,8 @@ class CryptoBalanceWidget extends StatelessWidget { padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: DashBoardRoundedCardWidget( customBorder: 30, - title: "Monero wallet is broken", - subTitle: "Here are the things that are broken:\n - " + title: "This wallet has encountered an issue", + subTitle: "Here are the things that you should note:\n - " +dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +"\n\nPlease restart your wallet and if it doesn't help contact our support.", onTap: () {}, diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 56a0e061b..d58d7535c 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -32,7 +32,6 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart'; import 'package:cake_wallet/view_model/settings/sync_mode.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; -import 'package:cake_wallet/wownero/wownero.dart' as wow; import 'package:cryptography/cryptography.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/cake_hive.dart'; @@ -485,6 +484,9 @@ abstract class DashboardViewModelBase with Store { @computed bool get hasSignMessages { + if (wallet.isHardwareWallet) { + return false; + } switch (wallet.type) { case WalletType.monero: case WalletType.litecoin: diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 3e45e8ba1..f2ea8eeb4 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -142,8 +142,17 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with _bestRate = 0; _calculateBestRate(); }); + + if (isElectrumWallet) { + bitcoin!.updateFeeRates(wallet); + } } + bool get isElectrumWallet => + wallet.type == WalletType.bitcoin || + wallet.type == WalletType.litecoin || + wallet.type == WalletType.bitcoinCash; + bool _useTorOnly; final Box<Trade> trades; final ExchangeTemplateStore _exchangeTemplateStore; diff --git a/macos/Podfile.lock b/macos/Podfile.lock index c2f37a3f3..8951a2dd1 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -17,15 +17,13 @@ PODS: - in_app_review (0.2.0): - FlutterMacOS - OrderedSet (5.0.0) - - package_info (0.0.1): - - FlutterMacOS - package_info_plus (0.0.1): - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - ReachabilitySwift (5.0.0) - - share_plus_macos (0.0.1): + - share_plus (0.0.1): - FlutterMacOS - shared_preferences_foundation (0.0.1): - Flutter @@ -46,10 +44,9 @@ DEPENDENCIES: - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`) - - package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - - share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`) + - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sp_scanner (from `Flutter/ephemeral/.symlinks/plugins/sp_scanner/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) @@ -77,14 +74,12 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral in_app_review: :path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos - package_info: - :path: Flutter/ephemeral/.symlinks/plugins/package_info/macos package_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin - share_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos + share_plus: + :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sp_scanner: @@ -104,11 +99,10 @@ SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c - package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2 - package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4 + share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sp_scanner: 269d96e0ec3173e69156be7239b95182be3b8303 url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 07dc7f5af..0d99c1c8c 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -94,10 +94,7 @@ dependencies: # ref: main socks5_proxy: ^1.0.4 flutter_svg: ^2.0.9 - polyseed: - git: - url: https://github.com/mrcyjanek/polyseed_dart - ref: f9adc68dbf879fefadeae8e86d1c2983f5a2cc3f + polyseed: ^0.0.6 nostr_tools: ^1.0.9 solana: ^0.30.1 bitcoin_base: @@ -105,7 +102,7 @@ dependencies: url: https://github.com/cake-tech/bitcoin_base ref: cake-update-v5 ledger_flutter: ^1.0.1 - hashlib: 1.12.0 + hashlib: ^1.19.2 dev_dependencies: flutter_test: diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index c91f24622..324d2d2ae 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.16.3" -MONERO_COM_BUILD_NUMBER=97 +MONERO_COM_VERSION="1.16.4" +MONERO_COM_BUILD_NUMBER=98 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.19.3" -CAKEWALLET_BUILD_NUMBER=224 +CAKEWALLET_VERSION="4.19.4" +CAKEWALLET_BUILD_NUMBER=225 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 e32b3e9f3..1405f7939 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.16.3" -MONERO_COM_BUILD_NUMBER=95 +MONERO_COM_VERSION="1.16.4" +MONERO_COM_BUILD_NUMBER=96 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.19.3" -CAKEWALLET_BUILD_NUMBER=262 +CAKEWALLET_VERSION="4.19.4" +CAKEWALLET_BUILD_NUMBER=263 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/linux/app_env.sh b/scripts/linux/app_env.sh index 729cf376b..bc2965193 100755 --- a/scripts/linux/app_env.sh +++ b/scripts/linux/app_env.sh @@ -14,8 +14,8 @@ if [ -n "$1" ]; then fi CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.9.2" -CAKEWALLET_BUILD_NUMBER=30 +CAKEWALLET_VERSION="1.9.4" +CAKEWALLET_BUILD_NUMBER=31 if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then echo "Wrong app type." diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 2f6d51a93..9487be2c8 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.6.2" -MONERO_COM_BUILD_NUMBER=27 +MONERO_COM_VERSION="1.6.4" +MONERO_COM_BUILD_NUMBER=28 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.12.2" -CAKEWALLET_BUILD_NUMBER=83 +CAKEWALLET_VERSION="1.12.4" +CAKEWALLET_BUILD_NUMBER=84 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then diff --git a/scripts/windows/build_exe_installer.iss b/scripts/windows/build_exe_installer.iss index 216f367ca..4d7838723 100644 --- a/scripts/windows/build_exe_installer.iss +++ b/scripts/windows/build_exe_installer.iss @@ -1,5 +1,5 @@ #define MyAppName "Cake Wallet" -#define MyAppVersion "0.0.4" +#define MyAppVersion "0.0.5" #define MyAppPublisher "Cake Labs LLC" #define MyAppURL "https://cakewallet.com/" #define MyAppExeName "CakeWallet.exe" From fe4b3e4eb05ca5037500778102e031a67243a9ee Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Sun, 18 Aug 2024 03:48:25 +0300 Subject: [PATCH 07/10] push haven fix --- cw_bitcoin/pubspec.lock | 6 +++--- cw_haven/lib/haven_wallet.dart | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 12274c1e6..cdb88946e 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -67,11 +67,11 @@ packages: source: git version: "1.0.1" bitcoin_base: - dependency: "direct main" + dependency: "direct overridden" description: path: "." - ref: cake-update-v4 - resolved-ref: "574486bfcdbbaf978dcd006b46fc8716f880da29" + ref: cake-update-v5 + resolved-ref: ff2b10eb27b0254ce4518d054332d97d77d9b380 url: "https://github.com/cake-tech/bitcoin_base" source: git version: "4.7.0" diff --git a/cw_haven/lib/haven_wallet.dart b/cw_haven/lib/haven_wallet.dart index c0ecbca68..317d9dc65 100644 --- a/cw_haven/lib/haven_wallet.dart +++ b/cw_haven/lib/haven_wallet.dart @@ -10,10 +10,8 @@ import 'package:cw_haven/haven_transaction_info.dart'; import 'package:cw_haven/haven_wallet_addresses.dart'; import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_haven/api/structs/pending_transaction.dart'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_haven/api/transaction_history.dart' as haven_transaction_history; -//import 'package:cw_haven/wallet.dart'; import 'package:cw_haven/api/wallet.dart' as haven_wallet; import 'package:cw_haven/api/transaction_history.dart' as transaction_history; import 'package:cw_haven/api/monero_output.dart'; @@ -123,7 +121,8 @@ abstract class HavenWalletBase login: node.login, password: node.password, useSSL: node.useSSL ?? false, - isLightWallet: false, // FIXME: hardcoded value + isLightWallet: false, + // FIXME: hardcoded value socksProxyAddress: node.socksProxyAddress); haven_wallet.setTrustedDaemon(node.trusted); @@ -419,4 +418,12 @@ abstract class HavenWalletBase @override String get password => _password; + + @override + Future<String> signMessage(String message, {String? address = null}) => + throw UnimplementedError(); + + @override + Future<bool> verifyMessage(String message, String signature, {String? address = null}) => + throw UnimplementedError(); } From 4071e460f687d4fe2e72368dfd3ed5a30ca2ca1f Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Sun, 18 Aug 2024 14:25:44 +0200 Subject: [PATCH 08/10] fix universal build (#1621) --- scripts/macos/build_monero_all.sh | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/scripts/macos/build_monero_all.sh b/scripts/macos/build_monero_all.sh index c934b4667..edc8efe81 100755 --- a/scripts/macos/build_monero_all.sh +++ b/scripts/macos/build_monero_all.sh @@ -23,12 +23,14 @@ then done else if [[ "x$1" == "xuniversal" ]]; then - ARCHS=(arm64 x86_64) + ARCHS=(x86_64 arm64) else ARCHS=$(uname -m) fi for COIN in monero wownero; do + MONERO_LIBS="" + WOWNERO_LIBS="" for ARCH in "${ARCHS[@]}"; do if [[ "$ARCH" == "arm64" ]]; then @@ -39,17 +41,19 @@ else HOST="${ARCH}-host-apple-darwin" fi - MONERO_LIBS=" -arch ${ARCH} ${MONEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib" - WOWNERO_LIBS=" -arch ${ARCH} ${WOWNEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib" + MONERO_LIBS="$MONERO_LIBS -arch ${ARCH} ${MONEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib" + WOWNERO_LIBS="$WOWNERO_LIBS -arch ${ARCH} ${WOWNEROC_RELEASE_DIR}/${HOST}_libwallet2_api_c.dylib" - if [[ ! $(uname -m) == $ARCH ]]; then - PRC="arch -${ARCH}" - fi + if [[ ! $(uname -m) == $ARCH ]]; then + PRC="arch -${ARCH}" + else + PRC="" + fi - pushd ../monero_c - $PRC ./build_single.sh ${COIN} ${HOST} $NPROC - unxz -f ./release/${COIN}/${HOST}_libwallet2_api_c.dylib.xz - popd + pushd ../monero_c + $PRC ./build_single.sh ${COIN} ${HOST} $NPROC + unxz -f ./release/${COIN}/${HOST}_libwallet2_api_c.dylib.xz + popd done done fi From 19c600ba10c4d72c984388073b0820e362c12bc6 Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Sun, 18 Aug 2024 17:15:23 +0300 Subject: [PATCH 09/10] update macos build number minor fixes --- .../desktop_widgets/desktop_wallet_selection_dropdown.dart | 4 ++-- lib/src/screens/dashboard/edit_token_page.dart | 2 +- lib/src/screens/exchange_trade/exchange_trade_page.dart | 2 +- lib/src/screens/new_wallet/new_wallet_page.dart | 2 +- lib/src/screens/root/root.dart | 2 +- lib/src/screens/send/widgets/send_card.dart | 2 +- scripts/macos/app_env.sh | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart index 94489a945..fd0eecac3 100644 --- a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart +++ b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart @@ -200,14 +200,14 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD } try { - if (context.mounted) { + if (mounted) { changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name)); } await widget.walletListViewModel.loadWallet(wallet); hideProgressText(); setState(() {}); } catch (e) { - if (context.mounted) { + if (mounted) { changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString())); } } diff --git a/lib/src/screens/dashboard/edit_token_page.dart b/lib/src/screens/dashboard/edit_token_page.dart index 59f7de9e5..dbb5f1aae 100644 --- a/lib/src/screens/dashboard/edit_token_page.dart +++ b/lib/src/screens/dashboard/edit_token_page.dart @@ -206,7 +206,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> { ), contractAddress: _contractAddressController.text, ); - if (context.mounted) { + if (mounted) { Navigator.pop(context); } } diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart index 4d3334f9f..0766a4562 100644 --- a/lib/src/screens/exchange_trade/exchange_trade_page.dart +++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart @@ -284,7 +284,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> { if (state is TransactionCommitted) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (context.mounted) { + if (mounted) { showPopUp<void>( context: context, builder: (BuildContext popupContext) { diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index cb451c056..471240877 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -95,7 +95,7 @@ class _WalletNameFormState extends State<WalletNameForm> { if (state is FailureState) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (context.mounted) { + if (mounted) { showPopUp<void>( context: context, builder: (_) { diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 8ce0ddde9..76c6c5cfd 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -219,7 +219,7 @@ class RootState extends State<Root> with WidgetsBindingObserver { void waitForWalletInstance(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { - if (context.mounted) { + if (mounted) { _walletReactionDisposer = reaction( (_) => widget.appStore.wallet, (WalletBase? wallet) { diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index 0a3de3e58..214d162ed 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -82,7 +82,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S if (initialPaymentRequest != null && sendViewModel.walletCurrencyName != initialPaymentRequest!.scheme.toLowerCase()) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - if (context.mounted) { + if (mounted) { showPopUp<void>( context: context, builder: (BuildContext context) { diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 9487be2c8..342831d65 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -22,7 +22,7 @@ MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="1.12.4" -CAKEWALLET_BUILD_NUMBER=84 +CAKEWALLET_BUILD_NUMBER=85 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then From 5449b94ba42c4e60d8cfd2a55696ee0f288a767a Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich <konstantinullrich12@gmail.com> Date: Mon, 19 Aug 2024 16:06:57 +0200 Subject: [PATCH 10/10] Windows fix (#1624) * CW-488 Fix missing Wownero logo * Temporary fix for windows --- .../desktop_wallet_selection_dropdown.dart | 29 +++++++++---------- lib/store/settings_store.dart | 10 +++++-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart index fd0eecac3..0dd3458b6 100644 --- a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart +++ b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart @@ -1,5 +1,4 @@ import 'package:another_flushbar/flushbar.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/entities/desktop_dropdown_item.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -8,8 +7,9 @@ import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart'; import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; -import 'package:cake_wallet/themes/extensions/menu_theme.dart'; import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/menu_theme.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; @@ -122,9 +122,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD } void _onSelectedWallet(WalletListItem selectedWallet) async { - if (selectedWallet.isCurrent || !selectedWallet.isEnabled) { - return; - } + if (selectedWallet.isCurrent || !selectedWallet.isEnabled) return; WidgetsBinding.instance.addPostFrameCallback((_) async { final confirmed = await showPopUp<bool>( @@ -149,9 +147,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD Image _imageFor({required WalletType type, bool? isTestnet}) { switch (type) { case WalletType.bitcoin: - if (isTestnet == true) { - return tBitcoinIcon; - } + if (isTestnet == true) return tBitcoinIcon; return bitcoinIcon; case WalletType.monero: return moneroIcon; @@ -173,6 +169,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD return solanaIcon; case WalletType.tron: return tronIcon; + case WalletType.wownero: + return wowneroIcon; default: return nonWalletTypeIcon; } @@ -180,24 +178,23 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD Future<void> _loadWallet(WalletListItem wallet) async { if (SettingsStoreBase.walletPasswordDirectInput) { - Navigator.of(context).pushNamed( - Routes.walletUnlockLoadable, + Navigator.of(context).pushNamed(Routes.walletUnlockLoadable, arguments: WalletUnlockArguments( callback: (bool isAuthenticatedSuccessfully, AuthPageState auth) async { if (isAuthenticatedSuccessfully) { auth.close(); setState(() {}); } - }, walletName: wallet.name, + }, + walletName: wallet.name, walletType: wallet.type)); return; } - widget._authService.authenticateAction(context, - onAuthSuccess: (isAuthenticatedSuccessfully) async { - if (!isAuthenticatedSuccessfully) { - return; - } + widget._authService.authenticateAction( + context, + onAuthSuccess: (isAuthenticatedSuccessfully) async { + if (!isAuthenticatedSuccessfully) return; try { if (mounted) { diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index df2c7767f..ee145195c 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -1549,8 +1549,14 @@ abstract class SettingsStoreBase with Store { final macInfo = await deviceInfoPlugin.macOsInfo; deviceName = macInfo.computerName; } else if (Platform.isWindows) { - final windowsInfo = await deviceInfoPlugin.windowsInfo; - deviceName = windowsInfo.productName; + try { + final windowsInfo = await deviceInfoPlugin.windowsInfo; + deviceName = windowsInfo.productName; + } catch (e) { + print(e); + print('likely digitalProductId is null wait till https://github.com/fluttercommunity/plus_plugins/pull/3188 is merged'); + deviceName = "Windows Device"; + } } return deviceName;