From 14167a85e8bb83f5c6f47e418fe65fef986a6810 Mon Sep 17 00:00:00 2001 From: Omar Hatem Date: Fri, 28 Aug 2026 10:07:16 +0800 Subject: [PATCH 1/4] v6.4.2 (#3566) * Rush Release please test quickly * Fix Zcash Lag --- .../new-ui/changelog/text/changelog_ar.json | 2 +- .../new-ui/changelog/text/changelog_bg.json | 2 +- .../new-ui/changelog/text/changelog_cs.json | 2 +- .../new-ui/changelog/text/changelog_de.json | 2 +- .../new-ui/changelog/text/changelog_en.json | 6 +-- .../new-ui/changelog/text/changelog_es.json | 2 +- .../new-ui/changelog/text/changelog_fa.json | 2 +- .../new-ui/changelog/text/changelog_fr.json | 2 +- .../new-ui/changelog/text/changelog_gn.json | 2 +- .../new-ui/changelog/text/changelog_ha.json | 2 +- .../new-ui/changelog/text/changelog_hi.json | 2 +- .../new-ui/changelog/text/changelog_hr.json | 2 +- .../new-ui/changelog/text/changelog_hy.json | 2 +- .../new-ui/changelog/text/changelog_id.json | 2 +- .../new-ui/changelog/text/changelog_it.json | 2 +- .../new-ui/changelog/text/changelog_ja.json | 2 +- .../new-ui/changelog/text/changelog_ko.json | 2 +- .../new-ui/changelog/text/changelog_my.json | 2 +- .../new-ui/changelog/text/changelog_nl.json | 2 +- .../new-ui/changelog/text/changelog_pl.json | 2 +- .../new-ui/changelog/text/changelog_pt.json | 2 +- .../new-ui/changelog/text/changelog_ru.json | 2 +- .../new-ui/changelog/text/changelog_th.json | 2 +- .../new-ui/changelog/text/changelog_tl.json | 2 +- .../new-ui/changelog/text/changelog_tr.json | 2 +- .../new-ui/changelog/text/changelog_uk.json | 2 +- .../new-ui/changelog/text/changelog_ur.json | 2 +- .../new-ui/changelog/text/changelog_vi.json | 2 +- .../new-ui/changelog/text/changelog_yo.json | 2 +- .../changelog/text/changelog_zh-cn.json | 2 +- cw_bitcoin/pubspec.yaml | 2 +- cw_bitcoin_cash/pubspec.yaml | 2 +- cw_dogecoin/pubspec.yaml | 2 +- ios/Podfile.lock | 50 ++++++++++++++++++- ios/Runner/InfoBase.plist | 1 - pubspec.lock | 12 ++--- scripts/android/app_env.sh | 8 +-- scripts/ios/app_env.sh | 8 +-- scripts/macos/app_env.sh | 8 +-- 39 files changed, 100 insertions(+), 57 deletions(-) diff --git a/assets/new-ui/changelog/text/changelog_ar.json b/assets/new-ui/changelog/text/changelog_ar.json index f839ec75c..08a75f976 100644 --- a/assets/new-ui/changelog/text/changelog_ar.json +++ b/assets/new-ui/changelog/text/changelog_ar.json @@ -1 +1 @@ -[{"title":"تحسينات زي كاش","description":"بعد الترحيل الناجح إلى IronWood الجديد، أضفنا المزيد من التحسينات إلى محفظة zcash"},{"title":"AnyPay على النحو المنشود","description":"الآن، سيؤدي لصق عنوان ما أو مسحه ضوئيًا من أي محفظة إلى توجيهك بشكل صحيح إما للتبديل أو الإرسال من المحفظة الصحيحة، والمزيد من التحسينات"},{"title":"تحسينات واجهة المستخدم","description":"تمت إضافة بعض عناصر واجهة المستخدم الجديدة خصيصًا لك"},{"title":"إصلاحات الشوائب","description":"سحق المزيد من الأخطاء"}] \ No newline at end of file +[{"title":"تحسينات AnyPay","description":"الآن، سيؤدي لصق عنوان ما أو مسحه ضوئيًا من أي محفظة إلى توجيهك بشكل صحيح إما للتبديل أو الإرسال من المحفظة الصحيحة، والمزيد من التحسينات"},{"title":"تحسينات واجهة المستخدم","description":"تمت إضافة بعض عناصر واجهة المستخدم الجديدة خصيصًا لك"},{"title":"إصلاحات الشوائب","description":"سحق المزيد من الأخطاء"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_bg.json b/assets/new-ui/changelog/text/changelog_bg.json index e8d541755..f7946afc9 100644 --- a/assets/new-ui/changelog/text/changelog_bg.json +++ b/assets/new-ui/changelog/text/changelog_bg.json @@ -1 +1 @@ -[{"title":"Подобрения на Zcash","description":"След успешната миграция към новия IronWood добавихме още подобрения към zcash портфейла"},{"title":"AnyPay според предназначението","description":"Сега поставянето или сканирането на адрес от който и да е портфейл ще ви насочи правилно към размяна или изпращане от правилния портфейл и много повече подобрения"},{"title":"Подобрения на потребителския интерфейс","description":"Добавени са някои нови елементи на потребителския интерфейс само за вас"},{"title":"Поправки на грешки","description":"Смачкани още грешки"}] \ No newline at end of file +[{"title":"Подобрения на AnyPay","description":"Сега поставянето или сканирането на адрес от който и да е портфейл ще ви насочи правилно към размяна или изпращане от правилния портфейл и много повече подобрения"},{"title":"Подобрения на потребителския интерфейс","description":"Добавени са някои нови елементи на потребителския интерфейс само за вас"},{"title":"Поправки на грешки","description":"Смачкани още грешки"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_cs.json b/assets/new-ui/changelog/text/changelog_cs.json index 80eeabebe..52d5e7797 100644 --- a/assets/new-ui/changelog/text/changelog_cs.json +++ b/assets/new-ui/changelog/text/changelog_cs.json @@ -1 +1 @@ -[{"title":"Zcash vylepšení","description":"Po úspěšné migraci na nový IronWood jsme přidali další vylepšení do zcash peněženky"},{"title":"AnyPay, jak bylo zamýšleno","description":"Nyní vložení nebo skenování adresy z libovolné peněženky vás správně nasměruje buď na výměnu nebo odeslání ze správné peněženky, a k mnoha dalším vylepšením"},{"title":"vylepšení uživatelského rozhraní","description":"Přidali jsme několik nových prvků uživatelského rozhraní jen pro vás"},{"title":"Opravy chyb","description":"Rozdrtil více brouků"}] \ No newline at end of file +[{"title":"Vylepšení AnyPay","description":"Nyní vložení nebo skenování adresy z libovolné peněženky vás správně nasměruje buď na výměnu nebo odeslání ze správné peněženky, a k mnoha dalším vylepšením"},{"title":"vylepšení uživatelského rozhraní","description":"Přidali jsme několik nových prvků uživatelského rozhraní jen pro vás"},{"title":"Opravy chyb","description":"Zmáčkl další brouky"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_de.json b/assets/new-ui/changelog/text/changelog_de.json index 5b3b29c05..bbbf2d6e2 100644 --- a/assets/new-ui/changelog/text/changelog_de.json +++ b/assets/new-ui/changelog/text/changelog_de.json @@ -1 +1 @@ -[{"title":"Zcash-Verbesserungen","description":"Nach der erfolgreichen Migration auf das neue IronWood haben wir weitere Verbesserungen an der Zcash-Wallet vorgenommen"},{"title":"AnyPay wie vorgesehen","description":"Wenn Sie nun eine Adresse aus einem beliebigen Wallet einfügen oder scannen, werden Sie direkt zum Tauschen oder Senden von dem richtigen Wallet weitergeleitet und es gibt noch viele weitere Verbesserungen"},{"title":"Verbesserungen der Benutzeroberfläche","description":"Einige neue UI-Elemente wurden speziell für Sie hinzugefügt"},{"title":"Fehlerbehebungen","description":"Weitere Bugs beseitigt"}] \ No newline at end of file +[{"title":"AnyPay-Verbesserungen","description":"Wenn Sie jetzt eine Adresse aus einem beliebigen Wallet einfügen oder scannen, werden Sie direkt zum Tauschen oder Senden von dem richtigen Wallet weitergeleitet und es gibt noch viele weitere Verbesserungen"},{"title":"Verbesserungen der Benutzeroberfläche","description":"Einige neue UI-Elemente wurden speziell für Sie hinzugefügt"},{"title":"Fehlerbehebungen","description":"Weitere Bugs beseitigt"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_en.json b/assets/new-ui/changelog/text/changelog_en.json index 7914f086e..bb20670d2 100644 --- a/assets/new-ui/changelog/text/changelog_en.json +++ b/assets/new-ui/changelog/text/changelog_en.json @@ -1,10 +1,6 @@ [ { - "title": "Zcash improvements", - "description": "After the successful migration to the new IronWood, we added more improvements to zcash wallet" - }, - { - "title": "AnyPay as Intended", + "title": "AnyPay Improvements", "description": "Now pasting or scanning an address from any wallet will point you correctly to either swapping or sending from the correct wallet, and much more improvements" }, { diff --git a/assets/new-ui/changelog/text/changelog_es.json b/assets/new-ui/changelog/text/changelog_es.json index cd8357218..ebff860ec 100644 --- a/assets/new-ui/changelog/text/changelog_es.json +++ b/assets/new-ui/changelog/text/changelog_es.json @@ -1 +1 @@ -[{"title":"Mejoras en Zcash","description":"Después de la migración exitosa al nuevo IronWood, agregamos más mejoras a la billetera zcash"},{"title":"AnyPay según lo previsto","description":"Ahora, pegar o escanear una dirección desde cualquier billetera le indicará correctamente si desea intercambiar o enviar desde la billetera correcta, y muchas más mejoras."},{"title":"Mejoras en la interfaz de usuario","description":"Se agregaron algunos elementos nuevos de la interfaz de usuario solo para ti."},{"title":"Corrección de errores","description":"Aplastado más errores"}] \ No newline at end of file +[{"title":"Mejoras en cualquier pago","description":"Ahora, pegar o escanear una dirección desde cualquier billetera le indicará correctamente si desea intercambiar o enviar desde la billetera correcta, y muchas más mejoras."},{"title":"Mejoras en la interfaz de usuario","description":"Se agregaron algunos elementos nuevos de la interfaz de usuario solo para ti."},{"title":"Corrección de errores","description":"Aplastado más errores"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_fa.json b/assets/new-ui/changelog/text/changelog_fa.json index 1ae3901ac..780416e12 100644 --- a/assets/new-ui/changelog/text/changelog_fa.json +++ b/assets/new-ui/changelog/text/changelog_fa.json @@ -1 +1 @@ -[{"title":"بهبود Zcash","description":"پس از انتقال موفقیت آمیز به IronWood جدید، بهبودهای بیشتری را به کیف پول zcash اضافه کردیم"},{"title":"AnyPay همانطور که در نظر گرفته شده است","description":"اکنون چسباندن یا اسکن یک آدرس از هر کیف پولی، شما را به درستی به تعویض یا ارسال از کیف پول صحیح و پیشرفت های بسیار بیشتر راهنمایی می کند."},{"title":"بهبودهای رابط کاربری","description":"برخی از عناصر رابط کاربری جدید را فقط برای شما اضافه کرد"},{"title":"رفع اشکال","description":"اشکالات بیشتری را له کرد"}] \ No newline at end of file +[{"title":"AnyPay Improvements","description":"اکنون چسباندن یا اسکن یک آدرس از هر کیف پولی، شما را به درستی به تعویض یا ارسال از کیف پول صحیح و پیشرفت های بسیار بیشتر راهنمایی می کند."},{"title":"بهبودهای رابط کاربری","description":"برخی از عناصر رابط کاربری جدید را فقط برای شما اضافه کرد"},{"title":"رفع اشکال","description":"اشکالات بیشتری را له کرد"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_fr.json b/assets/new-ui/changelog/text/changelog_fr.json index 399a014ce..8fa44d463 100644 --- a/assets/new-ui/changelog/text/changelog_fr.json +++ b/assets/new-ui/changelog/text/changelog_fr.json @@ -1 +1 @@ -[{"title":"Améliorations de Zcash","description":"Après la migration réussie vers le nouvel IronWood, nous avons ajouté d'autres améliorations au portefeuille zcash."},{"title":"AnyPay comme prévu","description":"Désormais, coller ou scanner une adresse à partir de n'importe quel portefeuille vous indiquera correctement soit l'échange, soit l'envoi à partir du bon portefeuille, et bien d'autres améliorations."},{"title":"Améliorations de l'interface utilisateur","description":"Ajout de nouveaux éléments d'interface utilisateur juste pour vous"},{"title":"Corrections de bugs","description":"Écrasé plus de bugs"}] \ No newline at end of file +[{"title":"Améliorations d'AnyPay","description":"Désormais, coller ou scanner une adresse à partir de n'importe quel portefeuille vous indiquera correctement soit l'échange, soit l'envoi à partir du bon portefeuille, et bien d'autres améliorations."},{"title":"Améliorations de l'interface utilisateur","description":"Ajout de nouveaux éléments d'interface utilisateur juste pour vous"},{"title":"Corrections de bugs","description":"Écrasé plus de bugs"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_gn.json b/assets/new-ui/changelog/text/changelog_gn.json index 5e26592d4..118c019c8 100644 --- a/assets/new-ui/changelog/text/changelog_gn.json +++ b/assets/new-ui/changelog/text/changelog_gn.json @@ -1 +1 @@ -[{"title":"Zcash ñemyatyrõ","description":"Ojejapo rire migración osẽ porãva IronWood pyahúpe, romoĩve mejora zcash billetera-pe"},{"title":"AnyPay Ojeipotaháicha","description":"Ko’áĝa emboja térã eescanea peteĩ dirección oimeraẽva billetera-gui nde señaláta hekopete taha’e intercambio térã emondo haĝua billetera hekopeteguágui, ha hetaiteve ñemyatyrõ"},{"title":"UI ñemyatyrõ","description":"Oñemoĩve peteĩ elemento UI pyahu ndéve g̃uarãnte"},{"title":"Umi mba’e’oka ñemyatyrõ","description":"Oñembopupu hetave mba’e’oka"}] \ No newline at end of file +[{"title":"AnyPay Ñemyatyrõ","description":"Ko’áĝa emboja térã eescanea peteĩ dirección oimeraẽva billetera-gui nde señaláta hekopete taha’e intercambio térã emondo haĝua billetera hekopeteguágui, ha hetaiteve ñemyatyrõ"},{"title":"UI ñemyatyrõ","description":"Oñemoĩve peteĩ elemento UI pyahu ndéve g̃uarãnte"},{"title":"Umi mba’e’oka ñemyatyrõ","description":"Oñembopupu hetave mba’e’oka"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_ha.json b/assets/new-ui/changelog/text/changelog_ha.json index 3b7cbfada..e652ce4ae 100644 --- a/assets/new-ui/changelog/text/changelog_ha.json +++ b/assets/new-ui/changelog/text/changelog_ha.json @@ -1 +1 @@ -[{"title":"Zcash ingantawa","description":"Bayan nasarar ƙaura zuwa sabon IronWood, mun ƙara ƙarin haɓakawa zuwa walat ɗin zcash"},{"title":"AnyPay kamar yadda aka nufa","description":"Yanzu liƙa ko duba adireshi daga kowane walat zai nuna maka daidai ga ko dai musanya ko aikawa daga ainihin walat ɗin, da ƙarin haɓakawa."},{"title":"UI inganta","description":"An ƙara wasu sabbin abubuwan UI don ku kawai"},{"title":"Gyaran kwaro","description":"Squashed karin kwari"}] \ No newline at end of file +[{"title":"AnyBiyan Ingantawa","description":"Yanzu liƙa ko duba adireshi daga kowane walat zai nuna maka daidai ga ko dai musanya ko aikawa daga ainihin walat ɗin, da ƙarin haɓakawa."},{"title":"UI inganta","description":"An ƙara wasu sabbin abubuwan UI don ku kawai"},{"title":"Gyaran kwaro","description":"Squashed karin kwari"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_hi.json b/assets/new-ui/changelog/text/changelog_hi.json index 9294d04a3..3a7653bc9 100644 --- a/assets/new-ui/changelog/text/changelog_hi.json +++ b/assets/new-ui/changelog/text/changelog_hi.json @@ -1 +1 @@ -[{"title":"ज़कैश में सुधार","description":"नए आयरनवुड में सफल माइग्रेशन के बाद, हमने zcash वॉलेट में और सुधार जोड़े"},{"title":"इच्छानुसार कोई भी भुगतान करें","description":"अब किसी भी वॉलेट से किसी पते को चिपकाने या स्कैन करने से आपको स्वैपिंग या सही वॉलेट से भेजने का सही संकेत मिलेगा, और भी बहुत कुछ सुधार होगा"},{"title":"UI improvements","description":"केवल आपके लिए कुछ ताज़ा यूआई तत्व जोड़े गए हैं"},{"title":"कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना","description":"अधिक कीड़ों को कुचल दिया"}] \ No newline at end of file +[{"title":"AnyPay सुधार","description":"अब किसी भी वॉलेट से किसी पते को चिपकाने या स्कैन करने से आपको स्वैपिंग या सही वॉलेट से भेजने का सही संकेत मिलेगा, और भी बहुत कुछ सुधार होगा"},{"title":"यूआई सुधार","description":"केवल आपके लिए कुछ ताज़ा यूआई तत्व जोड़े गए हैं"},{"title":"कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना","description":"अधिक कीड़ों को कुचल दिया"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_hr.json b/assets/new-ui/changelog/text/changelog_hr.json index abcd21ca1..2142a6759 100644 --- a/assets/new-ui/changelog/text/changelog_hr.json +++ b/assets/new-ui/changelog/text/changelog_hr.json @@ -1 +1 @@ -[{"title":"Zcash improvements","description":"Nakon uspješne migracije na novi IronWood, dodali smo još poboljšanja u zcash novčanik"},{"title":"AnyPay kako je predviđeno","description":"Sada će vas lijepljenje ili skeniranje adrese iz bilo kojeg novčanika ispravno usmjeriti na zamjenu ili slanje iz ispravnog novčanika i još mnogo poboljšanja"},{"title":"UI improvements","description":"Dodani su novi elementi korisničkog sučelja samo za vas"},{"title":"Ispravci grešaka","description":"Squashed more bugs"}] \ No newline at end of file +[{"title":"AnyPay poboljšanja","description":"Sada će vas lijepljenje ili skeniranje adrese iz bilo kojeg novčanika ispravno usmjeriti na zamjenu ili slanje iz ispravnog novčanika i još mnogo poboljšanja"},{"title":"Poboljšanja korisničkog sučelja","description":"Dodani su novi elementi korisničkog sučelja samo za vas"},{"title":"Ispravci grešaka","description":"Zgnječio još kukaca"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_hy.json b/assets/new-ui/changelog/text/changelog_hy.json index 4910b792b..f5939617b 100644 --- a/assets/new-ui/changelog/text/changelog_hy.json +++ b/assets/new-ui/changelog/text/changelog_hy.json @@ -1 +1 @@ -[{"title":"Zcash բարելավումներ","description":"Նոր IronWood-ի հաջող տեղափոխումից հետո մենք ավելի շատ բարելավումներ ենք ավելացրել zcash դրամապանակում"},{"title":"AnyPay, ինչպես նախատեսված է","description":"Այժմ ցանկացած դրամապանակից հասցե կպցնելը կամ սկանավորումը ձեզ ճիշտ կուղղորդի՝ կա՛մ փոխանակելու, կա՛մ ճիշտ դրամապանակից ուղարկելու և շատ ավելի բարելավումներ:"},{"title":"UI բարելավումներ","description":"Ավելացրել է մի քանի թարմ UI տարրեր հենց ձեզ համար"},{"title":"Սխալների շտկում","description":"Ճզմեց ավելի շատ սխալներ"}] \ No newline at end of file +[{"title":"AnyPay բարելավումներ","description":"Այժմ ցանկացած դրամապանակից հասցե կպցնելը կամ սկանավորումը ձեզ ճիշտ կուղղորդի՝ կա՛մ փոխանակելու, կա՛մ ճիշտ դրամապանակից ուղարկելու և շատ ավելի բարելավումներ:"},{"title":"UI բարելավումներ","description":"Ավելացրել է մի քանի թարմ UI տարրեր հենց ձեզ համար"},{"title":"Սխալների շտկում","description":"Ճզմեց ավելի շատ սխալներ"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_id.json b/assets/new-ui/changelog/text/changelog_id.json index f9be2b41d..162470665 100644 --- a/assets/new-ui/changelog/text/changelog_id.json +++ b/assets/new-ui/changelog/text/changelog_id.json @@ -1 +1 @@ -[{"title":"Peningkatan Zcash","description":"Setelah migrasi berhasil ke IronWood baru, kami menambahkan lebih banyak perbaikan pada dompet zcash"},{"title":"AnyPay sesuai tujuan","description":"Sekarang menempelkan atau memindai alamat dari dompet mana pun akan mengarahkan Anda dengan benar untuk menukar atau mengirim dari dompet yang benar, dan banyak lagi peningkatan lainnya"},{"title":"Peningkatan UI","description":"Menambahkan beberapa elemen UI baru hanya untuk Anda"},{"title":"Perbaikan bug","description":"Membasmi lebih banyak bug"}] \ No newline at end of file +[{"title":"Peningkatan AnyPay","description":"Sekarang menempelkan atau memindai alamat dari dompet mana pun akan mengarahkan Anda dengan benar untuk menukar atau mengirim dari dompet yang benar, dan banyak lagi peningkatan lainnya"},{"title":"Peningkatan UI","description":"Menambahkan beberapa elemen UI baru hanya untuk Anda"},{"title":"Perbaikan bug","description":"Membasmi lebih banyak bug"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_it.json b/assets/new-ui/changelog/text/changelog_it.json index c8afeaae1..9de58b171 100644 --- a/assets/new-ui/changelog/text/changelog_it.json +++ b/assets/new-ui/changelog/text/changelog_it.json @@ -1 +1 @@ -[{"title":"Miglioramenti di Zcash","description":"Dopo la riuscita migrazione al nuovo IronWood, abbiamo aggiunto ulteriori miglioramenti al portafoglio zcash"},{"title":"AnyPay come previsto","description":"Ora incollare o scansionare un indirizzo da qualsiasi portafoglio ti indicherà correttamente lo scambio o l'invio dal portafoglio corretto e molti altri miglioramenti"},{"title":"Miglioramenti dell'interfaccia utente","description":"Aggiunti alcuni nuovi elementi dell'interfaccia utente solo per te"},{"title":"Correzioni di bug","description":"Eliminati altri bug"}] \ No newline at end of file +[{"title":"Miglioramenti di AnyPay","description":"Ora incollare o scansionare un indirizzo da qualsiasi portafoglio ti indicherà correttamente lo scambio o l'invio dal portafoglio corretto e molti altri miglioramenti"},{"title":"Miglioramenti dell'interfaccia utente","description":"Aggiunti alcuni nuovi elementi dell'interfaccia utente solo per te"},{"title":"Correzioni di bug","description":"Eliminati altri bug"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_ja.json b/assets/new-ui/changelog/text/changelog_ja.json index 4af643e14..a798267f8 100644 --- a/assets/new-ui/changelog/text/changelog_ja.json +++ b/assets/new-ui/changelog/text/changelog_ja.json @@ -1 +1 @@ -[{"title":"Zcashの改善","description":"新しい IronWood への移行が成功した後、zcash ウォレットにさらに改良を加えました。"},{"title":"意図したとおりの AnyPay","description":"任意のウォレットからアドレスを貼り付けるかスキャンすると、正しいウォレットからの交換または送信が正しく示されるようになり、さらに多くの改善が行われました。"},{"title":"UIの改善","description":"あなたのためだけにいくつかの新しい UI 要素を追加しました"},{"title":"バグ修正","description":"より多くのバグを潰しました"}] \ No newline at end of file +[{"title":"AnyPayの改善","description":"任意のウォレットからアドレスを貼り付けるかスキャンすると、正しいウォレットからの交換または送信が正しく示されるようになり、さらに多くの改善が行われました。"},{"title":"UIの改善","description":"あなたのためだけにいくつかの新しい UI 要素を追加しました"},{"title":"バグ修正","description":"さらに多くのバグを潰しました"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_ko.json b/assets/new-ui/changelog/text/changelog_ko.json index 501612462..aceb6a4be 100644 --- a/assets/new-ui/changelog/text/changelog_ko.json +++ b/assets/new-ui/changelog/text/changelog_ko.json @@ -1 +1 @@ -[{"title":"Zcash 개선","description":"새로운 IronWood로 성공적으로 마이그레이션한 후 zcash 지갑에 더 많은 개선 사항을 추가했습니다."},{"title":"의도한 대로 AnyPay","description":"이제 지갑에서 주소를 붙여넣거나 스캔하면 올바른 지갑에서 주소를 교환하거나 보내는 것을 올바르게 가리킬 수 있으며 훨씬 더 많은 개선이 가능합니다."},{"title":"UI 개선","description":"당신을 위한 새로운 UI 요소를 추가했습니다."},{"title":"버그 수정","description":"더 많은 버그를 해결했습니다."}] \ No newline at end of file +[{"title":"애니페이 개선","description":"이제 지갑에서 주소를 붙여넣거나 스캔하면 올바른 지갑에서 주소를 교환하거나 보내는 것을 올바르게 가리킬 수 있으며 훨씬 더 많은 개선 사항이 있습니다."},{"title":"UI 개선","description":"당신을 위한 새로운 UI 요소를 추가했습니다."},{"title":"버그 수정","description":"더 많은 버그를 해결했습니다."}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_my.json b/assets/new-ui/changelog/text/changelog_my.json index 5d5905bee..f25bc55d9 100644 --- a/assets/new-ui/changelog/text/changelog_my.json +++ b/assets/new-ui/changelog/text/changelog_my.json @@ -1 +1 @@ -[{"title":"Zcash တိုးတက်မှုများ","description":"IronWood အသစ်သို့ အောင်မြင်စွာ ပြောင်းရွှေ့ပြီးနောက်၊ ကျွန်ုပ်တို့သည် zcash ပိုက်ဆံအိတ်သို့ နောက်ထပ် တိုးတက်မှုများကို ထည့်သွင်းခဲ့သည်။"},{"title":"ရည်ရွယ်ထားသည့်အတိုင်း AnyPay","description":"ယခု မည်သည့်ပိုက်ဆံအိတ်မှ လိပ်စာတစ်ခုကို ကူးထည့်ခြင်း သို့မဟုတ် စကင်န်ဖတ်ခြင်းသည် သင့်အား မှန်ကန်သောပိုက်ဆံအိတ်မှ လဲလှယ်ရန် သို့မဟုတ် ပေးပို့ခြင်းတို့ကို မှန်ကန်စွာ ညွှန်ပြပေးမည်ဖြစ်ပြီး ပိုမိုကောင်းမွန်လာစေရန်၊"},{"title":"UI တိုးတက်မှုများ","description":"သင့်အတွက်သာ လတ်ဆတ်သော UI အစိတ်အပိုင်းအချို့ကို ထည့်ထားသည်။"},{"title":"ချွတ်ယွင်းချက်ပြင်ဆင်မှုများ","description":"နောက်ထပ် ပိုးကောင်များကို နှိမ်နင်းခဲ့သည်။"}] \ No newline at end of file +[{"title":"AnyPay တိုးတက်မှုများ","description":"ယခု မည်သည့်ပိုက်ဆံအိတ်မှ လိပ်စာတစ်ခုကို ကူးထည့်ခြင်း သို့မဟုတ် စကင်န်ဖတ်ခြင်းသည် သင့်အား မှန်ကန်သောပိုက်ဆံအိတ်မှ လဲလှယ်ရန် သို့မဟုတ် ပေးပို့ခြင်းတို့ကို မှန်ကန်စွာ ညွှန်ပြပေးမည်ဖြစ်ပြီး ပိုမိုကောင်းမွန်လာစေရန်၊"},{"title":"UI တိုးတက်မှုများ","description":"သင့်အတွက်သာ လတ်ဆတ်သော UI အစိတ်အပိုင်းအချို့ကို ထည့်ထားသည်။"},{"title":"ချွတ်ယွင်းချက်ပြင်ဆင်မှုများ","description":"နောက်ထပ် ပိုးကောင်များကို နှိမ်နင်းခဲ့သည်။"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_nl.json b/assets/new-ui/changelog/text/changelog_nl.json index 6c551180a..22e5a608c 100644 --- a/assets/new-ui/changelog/text/changelog_nl.json +++ b/assets/new-ui/changelog/text/changelog_nl.json @@ -1 +1 @@ -[{"title":"Zcash-verbeteringen","description":"Na de succesvolle migratie naar het nieuwe IronWood hebben we meer verbeteringen aan de zcash-portemonnee toegevoegd"},{"title":"AnyPay zoals bedoeld","description":"Als u nu een adres uit een willekeurige portemonnee plakt of scant, wordt u correct verwezen naar het wisselen of verzenden vanuit de juiste portemonnee, en nog veel meer verbeteringen"},{"title":"UI-verbeteringen","description":"Speciaal voor jou een aantal nieuwe UI-elementen toegevoegd"},{"title":"Bugfixes","description":"Nog meer bugs geplet"}] \ No newline at end of file +[{"title":"AnyPay-verbeteringen","description":"Als u nu een adres uit een willekeurige portemonnee plakt of scant, wordt u correct verwezen naar het wisselen of verzenden vanuit de juiste portemonnee, en nog veel meer verbeteringen"},{"title":"UI-verbeteringen","description":"Speciaal voor jou een aantal nieuwe UI-elementen toegevoegd"},{"title":"Bugfixes","description":"Nog meer bugs geplet"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_pl.json b/assets/new-ui/changelog/text/changelog_pl.json index d78ba5818..68b526716 100644 --- a/assets/new-ui/changelog/text/changelog_pl.json +++ b/assets/new-ui/changelog/text/changelog_pl.json @@ -1 +1 @@ -[{"title":"Ulepszenia Zcasha","description":"Po udanej migracji do nowego IronWood, dodaliśmy kolejne ulepszenia do portfela Zcash"},{"title":"AnyPay zgodnie z przeznaczeniem","description":"Teraz wklejenie lub zeskanowanie adresu z dowolnego portfela wskaże prawidłowo opcję wymiany lub wysłania z odpowiedniego portfela oraz wiele innych ulepszeń"},{"title":"Ulepszenia interfejsu użytkownika","description":"Dodano kilka świeżych elementów interfejsu użytkownika specjalnie dla Ciebie"},{"title":"Poprawki błędów","description":"Zmiażdżono więcej błędów"}] \ No newline at end of file +[{"title":"Ulepszenia AnyPay","description":"Teraz wklejenie lub zeskanowanie adresu z dowolnego portfela wskaże prawidłowo opcję wymiany lub wysłania z odpowiedniego portfela oraz wiele innych ulepszeń"},{"title":"Ulepszenia interfejsu użytkownika","description":"Dodano kilka świeżych elementów interfejsu użytkownika specjalnie dla Ciebie"},{"title":"Poprawki błędów","description":"Zmiażdżono więcej błędów"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_pt.json b/assets/new-ui/changelog/text/changelog_pt.json index 6dee67564..02f3e18c9 100644 --- a/assets/new-ui/changelog/text/changelog_pt.json +++ b/assets/new-ui/changelog/text/changelog_pt.json @@ -1 +1 @@ -[{"title":"Melhorias no Zcash","description":"Após a migração bem-sucedida para o novo IronWood, adicionamos mais melhorias à carteira zcash"},{"title":"AnyPay conforme pretendido","description":"Agora, colar ou digitalizar um endereço de qualquer carteira indicará corretamente a troca ou o envio da carteira correta e muito mais melhorias"},{"title":"Melhorias na interface do usuário","description":"Adicionados alguns novos elementos de UI só para você"},{"title":"Correções de bugs","description":"Esmagou mais bugs"}] \ No newline at end of file +[{"title":"Melhorias no AnyPay","description":"Agora, colar ou digitalizar um endereço de qualquer carteira indicará corretamente a troca ou o envio da carteira correta e muito mais melhorias"},{"title":"Melhorias na interface do usuário","description":"Adicionados alguns novos elementos de UI só para você"},{"title":"Correções de bugs","description":"Esmagou mais bugs"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_ru.json b/assets/new-ui/changelog/text/changelog_ru.json index 0b82474d2..7b90b12a2 100644 --- a/assets/new-ui/changelog/text/changelog_ru.json +++ b/assets/new-ui/changelog/text/changelog_ru.json @@ -1 +1 @@ -[{"title":"Улучшения Zcash","description":"После успешного перехода на новый IronWood мы добавили дополнительные улучшения в кошелек zcash."},{"title":"AnyPay как задумано","description":"Теперь при вставке или сканировании адреса из любого кошелька вы сможете правильно выбрать обмен или отправку из правильного кошелька, а также множество других улучшений."},{"title":"Улучшения пользовательского интерфейса","description":"Специально для вас добавлено несколько свежих элементов пользовательского интерфейса."},{"title":"Исправления ошибок","description":"Устранено больше ошибок"}] \ No newline at end of file +[{"title":"Улучшения AnyPay","description":"Теперь при вставке или сканировании адреса из любого кошелька вы сможете правильно выбрать обмен или отправку из правильного кошелька, а также множество других улучшений."},{"title":"Улучшения пользовательского интерфейса","description":"Специально для вас добавлено несколько свежих элементов пользовательского интерфейса."},{"title":"Исправления ошибок","description":"Устранено больше ошибок"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_th.json b/assets/new-ui/changelog/text/changelog_th.json index 12b6844e3..2406e587d 100644 --- a/assets/new-ui/changelog/text/changelog_th.json +++ b/assets/new-ui/changelog/text/changelog_th.json @@ -1 +1 @@ -[{"title":"การปรับปรุง Zcash","description":"หลังจากการโยกย้ายไปยัง IronWood ใหม่ได้สำเร็จ เราได้เพิ่มการปรับปรุงเพิ่มเติมให้กับกระเป๋าเงิน zcash"},{"title":"AnyPay ตามที่ตั้งใจไว้","description":"ตอนนี้การวางหรือสแกนที่อยู่จากกระเป๋าเงินใด ๆ จะนำคุณไปสู่การแลกเปลี่ยนหรือส่งจากกระเป๋าเงินที่ถูกต้องอย่างถูกต้อง และการปรับปรุงอื่น ๆ อีกมากมาย"},{"title":"การปรับปรุง UI","description":"เพิ่มองค์ประกอบ UI ใหม่สำหรับคุณโดยเฉพาะ"},{"title":"แก้ไขข้อบกพร่อง","description":"กำจัดข้อบกพร่องเพิ่มเติม"}] \ No newline at end of file +[{"title":"การปรับปรุง AnyPay","description":"ตอนนี้การวางหรือสแกนที่อยู่จากกระเป๋าเงินใด ๆ จะนำคุณไปสู่การแลกเปลี่ยนหรือส่งจากกระเป๋าเงินที่ถูกต้องอย่างถูกต้อง และการปรับปรุงอื่น ๆ อีกมากมาย"},{"title":"การปรับปรุง UI","description":"เพิ่มองค์ประกอบ UI ใหม่สำหรับคุณโดยเฉพาะ"},{"title":"แก้ไขข้อบกพร่อง","description":"กำจัดข้อบกพร่องเพิ่มเติม"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_tl.json b/assets/new-ui/changelog/text/changelog_tl.json index 1bab34712..da2dc181b 100644 --- a/assets/new-ui/changelog/text/changelog_tl.json +++ b/assets/new-ui/changelog/text/changelog_tl.json @@ -1 +1 @@ -[{"title":"Mga pagpapabuti ng Zcash","description":"Pagkatapos ng matagumpay na paglipat sa bagong IronWood, nagdagdag kami ng higit pang mga pagpapahusay sa zcash wallet"},{"title":"AnyPay gaya ng Nilalayon","description":"Ngayon, ang pag-paste o pag-scan ng isang address mula sa anumang pitaka ay ituturo sa iyo nang tama sa alinman sa pagpapalit o pagpapadala mula sa tamang pitaka, at marami pang mga pagpapabuti"},{"title":"Mga pagpapabuti ng UI","description":"Nagdagdag ng ilang sariwang elemento ng UI para lang sa iyo"},{"title":"Mga pag-aayos ng bug","description":"Nilapit ang higit pang mga bug"}] \ No newline at end of file +[{"title":"Mga Pagpapabuti ng AnyPay","description":"Ngayon, ang pag-paste o pag-scan ng isang address mula sa anumang pitaka ay ituturo sa iyo nang tama sa alinman sa pagpapalit o pagpapadala mula sa tamang pitaka, at marami pang mga pagpapabuti"},{"title":"Mga pagpapabuti ng UI","description":"Nagdagdag ng ilang sariwang elemento ng UI para lang sa iyo"},{"title":"Mga pag-aayos ng bug","description":"Nilapit ang higit pang mga bug"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_tr.json b/assets/new-ui/changelog/text/changelog_tr.json index 9e2f8c917..2487474f9 100644 --- a/assets/new-ui/changelog/text/changelog_tr.json +++ b/assets/new-ui/changelog/text/changelog_tr.json @@ -1 +1 @@ -[{"title":"Zcash iyileştirmeleri","description":"Yeni IronWood'a başarılı geçişin ardından zcash cüzdanına daha fazla iyileştirme ekledik"},{"title":"AnyPay İstenildiği Gibi","description":"Artık herhangi bir cüzdandan bir adresi yapıştırmak veya taramak, sizi doğru cüzdandan değiştirmeye veya göndermeye yönlendirecek ve çok daha fazla iyileştirme yapacak"},{"title":"Kullanıcı arayüzü iyileştirmeleri","description":"Size özel bazı yeni kullanıcı arayüzü öğeleri eklendi"},{"title":"Hata düzeltmeleri","description":"Daha fazla hata giderildi"}] \ No newline at end of file +[{"title":"AnyPay İyileştirmeleri","description":"Artık herhangi bir cüzdandan bir adresi yapıştırmak veya taramak, sizi doğru cüzdandan değiştirmeye veya göndermeye yönlendirecek ve çok daha fazla iyileştirme yapacak"},{"title":"Kullanıcı arayüzü iyileştirmeleri","description":"Size özel bazı yeni kullanıcı arayüzü öğeleri eklendi"},{"title":"Hata düzeltmeleri","description":"Daha fazla hata giderildi"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_uk.json b/assets/new-ui/changelog/text/changelog_uk.json index ea4cf30a1..0c018e2e8 100644 --- a/assets/new-ui/changelog/text/changelog_uk.json +++ b/assets/new-ui/changelog/text/changelog_uk.json @@ -1 +1 @@ -[{"title":"Покращення Zcash","description":"Після успішного переходу на новий IronWood ми додали додаткові покращення до гаманця zcash"},{"title":"AnyPay за призначенням","description":"Тепер вставлення або сканування адреси з будь-якого гаманця правильно вкаже вас на обмін або надсилання з правильного гаманця, а також багато інших покращень"},{"title":"Покращення інтерфейсу користувача","description":"Додано кілька свіжих елементів інтерфейсу спеціально для вас"},{"title":"Виправлення помилок","description":"Роздавив більше помилок"}] \ No newline at end of file +[{"title":"Покращення AnyPay","description":"Тепер вставлення або сканування адреси з будь-якого гаманця правильно вкаже вас на обмін або надсилання з правильного гаманця, а також багато інших покращень"},{"title":"Покращення інтерфейсу користувача","description":"Додано кілька свіжих елементів інтерфейсу спеціально для вас"},{"title":"Виправлення помилок","description":"Роздавив більше помилок"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_ur.json b/assets/new-ui/changelog/text/changelog_ur.json index f0050e886..18a221bca 100644 --- a/assets/new-ui/changelog/text/changelog_ur.json +++ b/assets/new-ui/changelog/text/changelog_ur.json @@ -1 +1 @@ -[{"title":"Zcash میں بہتری","description":"نئے IronWood میں کامیاب منتقلی کے بعد، ہم نے zcash wallet میں مزید بہتری شامل کی۔"},{"title":"AnyPay جیسا کہ ارادہ ہے۔","description":"اب کسی بھی بٹوے سے ایڈریس پیسٹ یا اسکین کرنا آپ کو صحیح بٹوے سے تبدیل کرنے یا بھیجنے کی طرف صحیح طریقے سے اشارہ کرے گا، اور بہت زیادہ بہتری"},{"title":"UI میں بہتری","description":"صرف آپ کے لیے کچھ تازہ UI عناصر شامل کیے گئے۔"},{"title":"بگ کی اصلاحات","description":"مزید کیڑے کو کچل دیا۔"}] \ No newline at end of file +[{"title":"AnyPay میں بہتری","description":"اب کسی بھی بٹوے سے ایڈریس پیسٹ یا اسکین کرنا آپ کو صحیح بٹوے سے تبدیل کرنے یا بھیجنے کی طرف صحیح طریقے سے اشارہ کرے گا، اور بہت زیادہ بہتری"},{"title":"UI میں بہتری","description":"صرف آپ کے لیے کچھ تازہ UI عناصر شامل کیے گئے۔"},{"title":"بگ کی اصلاحات","description":"مزید کیڑے کو کچل دیا۔"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_vi.json b/assets/new-ui/changelog/text/changelog_vi.json index 5bbd9e52f..5d0798ae4 100644 --- a/assets/new-ui/changelog/text/changelog_vi.json +++ b/assets/new-ui/changelog/text/changelog_vi.json @@ -1 +1 @@ -[{"title":"Cải tiến Zcash","description":"Sau khi di chuyển thành công sang IronWood mới, chúng tôi đã bổ sung thêm nhiều cải tiến hơn cho ví zcash"},{"title":"AnyPay như dự định","description":"Giờ đây, việc dán hoặc quét địa chỉ từ bất kỳ ví nào sẽ chỉ cho bạn cách hoán đổi hoặc gửi từ đúng ví và nhiều cải tiến hơn nữa"},{"title":"Cải tiến giao diện người dùng","description":"Đã thêm một số thành phần UI mới dành riêng cho bạn"},{"title":"Sửa lỗi","description":"Dẹp nhiều lỗi hơn"}] \ No newline at end of file +[{"title":"Cải tiến AnyPay","description":"Giờ đây, việc dán hoặc quét địa chỉ từ bất kỳ ví nào sẽ chỉ cho bạn cách hoán đổi hoặc gửi từ đúng ví và nhiều cải tiến hơn nữa"},{"title":"Cải tiến giao diện người dùng","description":"Đã thêm một số thành phần UI mới dành riêng cho bạn"},{"title":"Sửa lỗi","description":"Dẹp nhiều lỗi hơn"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_yo.json b/assets/new-ui/changelog/text/changelog_yo.json index 1a8d9ac53..388cbdb7a 100644 --- a/assets/new-ui/changelog/text/changelog_yo.json +++ b/assets/new-ui/changelog/text/changelog_yo.json @@ -1 +1 @@ -[{"title":"Awọn ilọsiwaju Zcash","description":"Lẹhin ijira aṣeyọri si IronWood tuntun, a ṣafikun awọn ilọsiwaju diẹ sii si apamọwọ zcash"},{"title":"AnyPay bi a ti pinnu","description":"Ni bayi titọ tabi ṣiṣayẹwo adirẹsi kan lati eyikeyi apamọwọ yoo tọka si ni deede si boya paarọ tabi firanṣẹ lati apamọwọ to pe, ati awọn ilọsiwaju pupọ diẹ sii."},{"title":"UI awọn ilọsiwaju","description":"Ṣafikun diẹ ninu awọn eroja UI tuntun kan fun ọ"},{"title":"Awọn atunṣe kokoro","description":"Squashed diẹ idun"}] \ No newline at end of file +[{"title":"Awọn ilọsiwaju AnyPay","description":"Ni bayi titọ tabi ṣiṣayẹwo adirẹsi kan lati eyikeyi apamọwọ yoo tọka si ni deede si boya paarọ tabi firanṣẹ lati apamọwọ to pe, ati awọn ilọsiwaju pupọ diẹ sii."},{"title":"UI awọn ilọsiwaju","description":"Ṣafikun diẹ ninu awọn eroja UI tuntun kan fun ọ"},{"title":"Awọn atunṣe kokoro","description":"Squashed diẹ idun"}] \ No newline at end of file diff --git a/assets/new-ui/changelog/text/changelog_zh-cn.json b/assets/new-ui/changelog/text/changelog_zh-cn.json index c33d6e328..c5a8fa4a8 100644 --- a/assets/new-ui/changelog/text/changelog_zh-cn.json +++ b/assets/new-ui/changelog/text/changelog_zh-cn.json @@ -1 +1 @@ -[{"title":"Zcash 的改进","description":"成功迁移到新的 IronWood 后,我们对 zcash 钱包添加了更多改进"},{"title":"AnyPay 符合预期","description":"现在,从任何钱包粘贴或扫描地址都会正确地指示您从正确的钱包进行交换或发送,以及更多改进"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"错误修复","description":"消除了更多错误"}] \ No newline at end of file +[{"title":"AnyPay 改进","description":"现在,从任何钱包粘贴或扫描地址将正确地指示您从正确的钱包进行交换或发送,以及更多改进"},{"title":"用户界面改进","description":"为您添加了一些新鲜的 UI 元素"},{"title":"错误修复","description":"消除了更多错误"}] \ No newline at end of file diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index b447dda68..3eb747a72 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -88,7 +88,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: bda0e2904effa799ec835b4578cc3fc5d31caa78 + ref: 4e41f96f4838139895c65c3f49109d05af5d46aa pointycastle: 3.7.4 ffi: 2.1.0 intl: any diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 5d0c46d42..77956e97e 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -43,7 +43,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: bda0e2904effa799ec835b4578cc3fc5d31caa78 + ref: 4e41f96f4838139895c65c3f49109d05af5d46aa # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_dogecoin/pubspec.yaml b/cw_dogecoin/pubspec.yaml index a93ea377b..146c7abd0 100644 --- a/cw_dogecoin/pubspec.yaml +++ b/cw_dogecoin/pubspec.yaml @@ -40,7 +40,7 @@ dependency_overrides: bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base - ref: bda0e2904effa799ec835b4578cc3fc5d31caa78 + ref: 4e41f96f4838139895c65c3f49109d05af5d46aa # For information on the generic Dart part of this file, see the diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f10f7d8ef..df4391855 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,9 +1,15 @@ PODS: - bitbox_flutter (0.0.1): - Flutter + - breez_sdk_spark_flutter (0.23.0): + - Flutter - connectivity_plus (0.0.1): - Flutter - CryptoSwift (1.8.4) + - cw_decred (0.0.1): + - Flutter + - cw_mweb (0.0.1): + - Flutter - device_display_brightness (0.0.1): - Flutter - device_info_plus (0.0.1): @@ -61,6 +67,8 @@ PODS: - Flutter - flutter_mailer (0.0.1): - Flutter + - flutter_native_splash (2.4.3): + - Flutter - flutter_secure_storage (6.0.0): - Flutter - fluttertoast (0.0.2): @@ -71,9 +79,13 @@ PODS: - Flutter - integration_test (0.0.1): - Flutter + - local_auth_darwin (0.0.1): + - Flutter + - FlutterMacOS - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter + - payjoin_flutter (0.23.0) - permission_handler_apple (9.4.8): - Flutter - quick_actions_ios (0.0.1): @@ -81,6 +93,10 @@ PODS: - reown_yttrium (0.0.1): - Flutter - YttriumWrapper (= 0.8.35) + - rive_common (0.0.1): + - Flutter + - rlz (0.0.1): + - Flutter - SDWebImage (5.21.2): - SDWebImage/Core (= 5.21.2) - SDWebImage/Core (5.21.2) @@ -91,6 +107,8 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - sp_scanner (0.0.1): + - Flutter - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS @@ -135,8 +153,11 @@ PODS: DEPENDENCIES: - bitbox_flutter (from `.symlinks/plugins/bitbox_flutter/ios`) + - breez_sdk_spark_flutter (from `.symlinks/plugins/breez_sdk_spark_flutter/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - CryptoSwift + - cw_decred (from `.symlinks/plugins/cw_decred/ios`) + - cw_mweb (from `.symlinks/plugins/cw_mweb/ios`) - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) @@ -148,18 +169,24 @@ DEPENDENCIES: - flutter_local_authentication (from `.symlinks/plugins/flutter_local_authentication/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`) + - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - in_app_review (from `.symlinks/plugins/in_app_review/ios`) - integration_test (from `.symlinks/plugins/integration_test/ios`) + - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - payjoin_flutter (from `.symlinks/plugins/payjoin_flutter/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`) - reown_yttrium (from `.symlinks/plugins/reown_yttrium/ios`) + - rive_common (from `.symlinks/plugins/rive_common/ios`) + - rlz (from `.symlinks/plugins/rlz/ios`) - sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sp_scanner (from `.symlinks/plugins/sp_scanner/ios`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) - torch_dart (from `.symlinks/plugins/torch_dart/ios`) @@ -182,8 +209,14 @@ SPEC REPOS: EXTERNAL SOURCES: bitbox_flutter: :path: ".symlinks/plugins/bitbox_flutter/ios" + breez_sdk_spark_flutter: + :path: ".symlinks/plugins/breez_sdk_spark_flutter/ios" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" + cw_decred: + :path: ".symlinks/plugins/cw_decred/ios" + cw_mweb: + :path: ".symlinks/plugins/cw_mweb/ios" device_display_brightness: :path: ".symlinks/plugins/device_display_brightness/ios" device_info_plus: @@ -206,6 +239,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_mailer: :path: ".symlinks/plugins/flutter_mailer/ios" + flutter_native_splash: + :path: ".symlinks/plugins/flutter_native_splash/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" fluttertoast: @@ -216,20 +251,30 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/in_app_review/ios" integration_test: :path: ".symlinks/plugins/integration_test/ios" + local_auth_darwin: + :path: ".symlinks/plugins/local_auth_darwin/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" + payjoin_flutter: + :path: ".symlinks/plugins/payjoin_flutter/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" quick_actions_ios: :path: ".symlinks/plugins/quick_actions_ios/ios" reown_yttrium: :path: ".symlinks/plugins/reown_yttrium/ios" + rive_common: + :path: ".symlinks/plugins/rive_common/ios" + rlz: + :path: ".symlinks/plugins/rlz/ios" sensitive_clipboard: :path: ".symlinks/plugins/sensitive_clipboard/ios" share_plus: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sp_scanner: + :path: ".symlinks/plugins/sp_scanner/ios" sqflite_darwin: :path: ".symlinks/plugins/sqflite_darwin/darwin" sqlite3_flutter_libs: @@ -247,6 +292,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: bitbox_flutter: 9505732798041c413152669751beeaecc5fe400f + breez_sdk_spark_flutter: f02552ffcff6012e5a4849517d78376ad1046250 connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6 @@ -277,6 +323,8 @@ SPEC CHECKSUMS: permission_handler_apple: 92d754bbaa7361d436db2d6c3c1c2a0fdcec462e quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779 reown_yttrium: cee334ade64725b1d83f7b34c706a6aae2696d58 + rive_common: dd421daaf9ae69f0125aa761dd96abd278399952 + rlz: 3f4022361f540a5c26d9d2474fea1d2455b69d8d SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a @@ -288,7 +336,7 @@ SPEC CHECKSUMS: SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 torch_dart: f4620705d10f05492fab047f2fa1c3a600e7d17d uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152 - universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914 + universal_ble: a322ebabee64f0ec27a313e89a5dd6967f37a60f url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966 diff --git a/ios/Runner/InfoBase.plist b/ios/Runner/InfoBase.plist index a29c3d58f..43eec935d 100644 --- a/ios/Runner/InfoBase.plist +++ b/ios/Runner/InfoBase.plist @@ -201,7 +201,6 @@ solana solana-wallet - solana_wallet diff --git a/pubspec.lock b/pubspec.lock index 83f756386..cbcdbf567 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -280,11 +280,11 @@ packages: dependency: "direct overridden" description: path: "." - ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb - resolved-ref: e18b6437daaf0572de6aea2439c2ec4d22658bbb + ref: "5943a3e773203f21728f87f1c0779040db8f2c28" + resolved-ref: "5943a3e773203f21728f87f1c0779040db8f2c28" url: "https://github.com/breez/breez-sdk-spark-flutter" source: git - version: "0.14.0" + version: "0.23.0" bs58: dependency: "direct overridden" description: @@ -2600,9 +2600,9 @@ packages: dependency: "direct overridden" description: path: "." - ref: "9457422fce3f1524437f6a1429200f048931a2fe" - resolved-ref: "9457422fce3f1524437f6a1429200f048931a2fe" - url: "https://github.com/MrCyjaneK/rive_common" + ref: "34ef174e87dc4a29e728babfaad8dd9464b704ae" + resolved-ref: "34ef174e87dc4a29e728babfaad8dd9464b704ae" + url: "https://github.com/malik1004x/rive_common" source: git version: "0.4.15" riverpod: diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index b71f25d1a..e62272ee9 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -14,15 +14,15 @@ TYPES=($MONERO_COM $CAKEWALLET) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="6.4.1" -MONERO_COM_BUILD_NUMBER=4165 +MONERO_COM_VERSION="6.4.2" +MONERO_COM_BUILD_NUMBER=4166 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.1" -CAKEWALLET_BUILD_NUMBER=4420 +CAKEWALLET_VERSION="6.4.2" +CAKEWALLET_BUILD_NUMBER=4421 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 270efdb27..9bf2dc05b 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -12,13 +12,13 @@ TYPES=($MONERO_COM $CAKEWALLET) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="6.4.1" -MONERO_COM_BUILD_NUMBER=171 +MONERO_COM_VERSION="6.4.2" +MONERO_COM_BUILD_NUMBER=172 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.1" -CAKEWALLET_BUILD_NUMBER=434 +CAKEWALLET_VERSION="6.4.2" +CAKEWALLET_BUILD_NUMBER=435 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index e92693a06..2683183af 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="6.4.1" -MONERO_COM_BUILD_NUMBER=82 +MONERO_COM_VERSION="6.4.2" +MONERO_COM_BUILD_NUMBER=83 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.1" -CAKEWALLET_BUILD_NUMBER=150 +CAKEWALLET_VERSION="6.4.2" +CAKEWALLET_BUILD_NUMBER=151 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then From 905db64f770200ceb181ae5ebb1fcd3b490dca90 Mon Sep 17 00:00:00 2001 From: cyan Date: Fri, 28 Aug 2026 15:49:51 +0800 Subject: [PATCH 2/4] feat: zano hf + bip39 (#3359) * feat: bip39 zano hf * fix: correct monero_c hash * lockfile [skip ci] * fix: zano: proper bip32 fix: zano respect 24 word setting fix: rename / delete * fix: nonBip39WalletTypes * fix: zano wallet rename * fix: passphrase store zano --------- Co-authored-by: Omar Hatem --- cw_monero/pubspec.yaml | 2 +- cw_wownero/pubspec.yaml | 2 +- cw_zano/lib/api/model/transfer.dart | 9 +- cw_zano/lib/bip39_seed.dart | 60 +++ cw_zano/lib/get_height_by_data.txt | 4 + cw_zano/lib/get_height_by_date.dart | 467 ++++++++++++++++++ cw_zano/lib/zano_utils.dart | 11 +- cw_zano/lib/zano_wallet.dart | 318 ++++++++++-- cw_zano/lib/zano_wallet_api.dart | 109 +++- cw_zano/lib/zano_wallet_service.dart | 55 ++- cw_zano/pubspec.yaml | 4 +- cw_zano/test/bip39_seed_test.dart | 38 ++ lib/core/wallet_creation_service.dart | 2 +- lib/di.dart | 2 +- lib/reactions/wallet_utils.dart | 2 +- .../wallet_restore_from_seed_form.dart | 7 +- .../screens/restore/wallet_restore_page.dart | 9 +- lib/src/widgets/blockchain_height_widget.dart | 3 + .../advanced_privacy_settings_view_model.dart | 2 +- .../wallet_groups_display_view_model.dart | 7 +- lib/view_model/wallet_new_vm.dart | 1 + lib/view_model/wallet_restore_view_model.dart | 24 +- lib/zano/cw_zano.dart | 27 +- pubspec.lock | 4 +- pubspec_overrides.yaml | 2 +- scripts/prepare_moneroc.sh | 2 +- tool/configure.dart | 7 +- 27 files changed, 1074 insertions(+), 106 deletions(-) create mode 100644 cw_zano/lib/bip39_seed.dart create mode 100644 cw_zano/lib/get_height_by_data.txt create mode 100644 cw_zano/lib/get_height_by_date.dart create mode 100644 cw_zano/test/bip39_seed_test.dart diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index 3f1c10f7b..04d3f3997 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c.git - ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d + ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 path: impls/monero.dart mutex: ^3.1.0 ledger_flutter_plus: ^1.4.1 diff --git a/cw_wownero/pubspec.yaml b/cw_wownero/pubspec.yaml index 6f9902452..da8f90997 100644 --- a/cw_wownero/pubspec.yaml +++ b/cw_wownero/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c.git - ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d + ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 path: impls/monero.dart mutex: ^3.1.0 diff --git a/cw_zano/lib/api/model/transfer.dart b/cw_zano/lib/api/model/transfer.dart index 2d9b51d5c..37a73085a 100644 --- a/cw_zano/lib/api/model/transfer.dart +++ b/cw_zano/lib/api/model/transfer.dart @@ -66,8 +66,13 @@ class Transfer { ? [] : (json['remote_aliases'] as List).cast(), showSender: json['show_sender'] as bool? ?? false, - subtransfers: (json['subtransfers'] as List? ?? []) - .map((e) => Subtransfer.fromJson(e as Map)) + subtransfers: (json['subtransfers_by_pid'] as List? ?? []) + .whereType>() + .expand( + (group) => (group['subtransfers'] as List? ?? []) + .whereType>() + .map(Subtransfer.fromJson), + ) .toList(), timestamp: json['timestamp'] as int? ?? 0, transferInternalIndex: json['transfer_internal_index'] == null diff --git a/cw_zano/lib/bip39_seed.dart b/cw_zano/lib/bip39_seed.dart new file mode 100644 index 000000000..b054a5dcb --- /dev/null +++ b/cw_zano/lib/bip39_seed.dart @@ -0,0 +1,60 @@ +import 'dart:typed_data'; + +import 'package:bip32/bip32.dart' as bip32; +import 'package:bip39/bip39.dart' as bip39; +import 'package:bip39/src/wordlists/english.dart' as bip39_english; + +bool isBip39Seed(String mnemonic) => bip39.validateMnemonic(mnemonic); + +List get bip39EnglishWords => List.from(bip39_english.WORDLIST); + +String generateBip39Mnemonic({int strength = 128}) => + bip39.generateMnemonic(strength: strength); + +String getSecretDerivationFromBip39(String mnemonic, {String passphrase = ''}) { + final seed = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase); + + final bip32KeyPair = bip32.BIP32.fromSeed(seed).derivePath("m/44'/128'/0'/0/0"); + + return _reduceECKey(bip32KeyPair.privateKey!).toHexString(); +} + +const _ed25519CurveOrder = "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"; + +Uint8List _reduceECKey(Uint8List buffer) { + final curveOrder = BigInt.parse(_ed25519CurveOrder, radix: 16); + final bigNumber = _readBytes(buffer); + + var result = bigNumber % curveOrder; + + final resultBuffer = Uint8List(32); + for (var i = 0; i < 32; i++) { + resultBuffer[i] = (result & BigInt.from(0xff)).toInt(); + result = result >> 8; + } + + return resultBuffer; +} + +/// Read BigInt from a little-endian Uint8List +/// From https://github.com/dart-lang/sdk/issues/32803#issuecomment-387405784 +BigInt _readBytes(Uint8List bytes) { + BigInt read(int start, int end) { + if (end - start <= 4) { + var result = 0; + for (int i = end - 1; i >= start; i--) { + result = result * 256 + bytes[i]; + } + return BigInt.from(result); + } + final mid = start + ((end - start) >> 1); + return read(start, mid) + read(mid, end) * (BigInt.one << ((mid - start) * 8)); + } + + return read(0, bytes.length); +} + +extension on Uint8List { + String toHexString() => + map((b) => b.toRadixString(16).padLeft(2, '0')).join(); +} diff --git a/cw_zano/lib/get_height_by_data.txt b/cw_zano/lib/get_height_by_data.txt new file mode 100644 index 000000000..43df05f1e --- /dev/null +++ b/cw_zano/lib/get_height_by_data.txt @@ -0,0 +1,4 @@ +NODE=http://37.27.100.59:10500/json_rpc +HEIGHT=$(curl -s -X POST $NODE -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['height'])") +echo "_Checkpoint($(curl -s -X POST $NODE -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"0","method":"getblockheaderbyheight","params":{"height":1}}' | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['block_header']['timestamp'])"), 1)," +for i in $(seq 1 $((HEIGHT/10000))); do echo "_Checkpoint($(curl -s -X POST $NODE -H 'Content-Type: application/json' -d "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getblockheaderbyheight\",\"params\":{\"height\":${i}0000}}" | python3 -c "import sys,json; print(json.load(sys.stdin)['result']['block_header']['timestamp'])"), ${i}0000),"; done diff --git a/cw_zano/lib/get_height_by_date.dart b/cw_zano/lib/get_height_by_date.dart new file mode 100644 index 000000000..83cef7328 --- /dev/null +++ b/cw_zano/lib/get_height_by_date.dart @@ -0,0 +1,467 @@ +class ZanoHeight { + static final List<_Checkpoint> _points = [ + _Checkpoint(1557342384, 1), + _Checkpoint(1557906733, 10000), + _Checkpoint(1558516097, 20000), + _Checkpoint(1559119125, 30000), + _Checkpoint(1559741805, 40000), + _Checkpoint(1560341175, 50000), + _Checkpoint(1560948480, 60000), + _Checkpoint(1561555965, 70000), + _Checkpoint(1562142135, 80000), + _Checkpoint(1562749400, 90000), + _Checkpoint(1563354315, 100000), + _Checkpoint(1563958673, 110000), + _Checkpoint(1564559835, 120000), + _Checkpoint(1565159325, 130000), + _Checkpoint(1565772195, 140000), + _Checkpoint(1566389235, 150000), + _Checkpoint(1566992793, 160000), + _Checkpoint(1567597678, 170000), + _Checkpoint(1568204955, 180000), + _Checkpoint(1568812530, 190000), + _Checkpoint(1569418329, 200000), + _Checkpoint(1570035660, 210000), + _Checkpoint(1570641964, 220000), + _Checkpoint(1571242140, 230000), + _Checkpoint(1571841282, 240000), + _Checkpoint(1572443911, 250000), + _Checkpoint(1573049280, 260000), + _Checkpoint(1573653255, 270000), + _Checkpoint(1574251680, 280000), + _Checkpoint(1574854984, 290000), + _Checkpoint(1575459060, 300000), + _Checkpoint(1576064640, 310000), + _Checkpoint(1576665225, 320000), + _Checkpoint(1577271045, 330000), + _Checkpoint(1577867835, 340000), + _Checkpoint(1578470370, 350000), + _Checkpoint(1579078170, 360000), + _Checkpoint(1579674765, 370000), + _Checkpoint(1580277860, 380000), + _Checkpoint(1580878155, 390000), + _Checkpoint(1581482220, 400000), + _Checkpoint(1582087577, 410000), + _Checkpoint(1582689270, 420000), + _Checkpoint(1583284005, 430000), + _Checkpoint(1583880062, 440000), + _Checkpoint(1584480692, 450000), + _Checkpoint(1585085520, 460000), + _Checkpoint(1585694261, 470000), + _Checkpoint(1586292210, 480000), + _Checkpoint(1586893822, 490000), + _Checkpoint(1587498656, 500000), + _Checkpoint(1588099364, 510000), + _Checkpoint(1588696710, 520000), + _Checkpoint(1589300843, 530000), + _Checkpoint(1589904930, 540000), + _Checkpoint(1590499185, 550000), + _Checkpoint(1591111133, 560000), + _Checkpoint(1591715587, 570000), + _Checkpoint(1592316375, 580000), + _Checkpoint(1592918012, 590000), + _Checkpoint(1593521050, 600000), + _Checkpoint(1594123886, 610000), + _Checkpoint(1594725660, 620000), + _Checkpoint(1595326710, 630000), + _Checkpoint(1595929088, 640000), + _Checkpoint(1596535020, 650000), + _Checkpoint(1597132395, 660000), + _Checkpoint(1597740870, 670000), + _Checkpoint(1598339827, 680000), + _Checkpoint(1598945010, 690000), + _Checkpoint(1599547530, 700000), + _Checkpoint(1600153050, 710000), + _Checkpoint(1600754010, 720000), + _Checkpoint(1601355810, 730000), + _Checkpoint(1601956635, 740000), + _Checkpoint(1602558615, 750000), + _Checkpoint(1603155648, 760000), + _Checkpoint(1603759399, 770000), + _Checkpoint(1604365586, 780000), + _Checkpoint(1604966602, 790000), + _Checkpoint(1605564777, 800000), + _Checkpoint(1606168023, 810000), + _Checkpoint(1606772409, 820000), + _Checkpoint(1607377110, 830000), + _Checkpoint(1607988084, 840000), + _Checkpoint(1608593385, 850000), + _Checkpoint(1609196310, 860000), + _Checkpoint(1609793426, 870000), + _Checkpoint(1610398975, 880000), + _Checkpoint(1610999055, 890000), + _Checkpoint(1611601290, 900000), + _Checkpoint(1612208050, 910000), + _Checkpoint(1612805250, 920000), + _Checkpoint(1613409645, 930000), + _Checkpoint(1614003255, 940000), + _Checkpoint(1614600803, 950000), + _Checkpoint(1615202091, 960000), + _Checkpoint(1615802123, 970000), + _Checkpoint(1616414192, 980000), + _Checkpoint(1617015705, 990000), + _Checkpoint(1617613785, 1000000), + _Checkpoint(1618218467, 1010000), + _Checkpoint(1618821464, 1020000), + _Checkpoint(1619424052, 1030000), + _Checkpoint(1620027510, 1040000), + _Checkpoint(1620630585, 1050000), + _Checkpoint(1621232355, 1060000), + _Checkpoint(1621832220, 1070000), + _Checkpoint(1622426032, 1080000), + _Checkpoint(1623041250, 1090000), + _Checkpoint(1623644732, 1100000), + _Checkpoint(1624244801, 1110000), + _Checkpoint(1624848450, 1120000), + _Checkpoint(1625449290, 1130000), + _Checkpoint(1626049974, 1140000), + _Checkpoint(1626656033, 1150000), + _Checkpoint(1627255830, 1160000), + _Checkpoint(1627855505, 1170000), + _Checkpoint(1628464065, 1180000), + _Checkpoint(1629064455, 1190000), + _Checkpoint(1629665715, 1200000), + _Checkpoint(1630268475, 1210000), + _Checkpoint(1630870911, 1220000), + _Checkpoint(1631475471, 1230000), + _Checkpoint(1632071441, 1240000), + _Checkpoint(1632677576, 1250000), + _Checkpoint(1633286445, 1260000), + _Checkpoint(1633884645, 1270000), + _Checkpoint(1634480355, 1280000), + _Checkpoint(1635077039, 1290000), + _Checkpoint(1635679740, 1300000), + _Checkpoint(1636284345, 1310000), + _Checkpoint(1636882865, 1320000), + _Checkpoint(1637482276, 1330000), + _Checkpoint(1638082296, 1340000), + _Checkpoint(1638682601, 1350000), + _Checkpoint(1639287225, 1360000), + _Checkpoint(1639884465, 1370000), + _Checkpoint(1640484903, 1380000), + _Checkpoint(1641084033, 1390000), + _Checkpoint(1641688500, 1400000), + _Checkpoint(1642286685, 1410000), + _Checkpoint(1642886842, 1420000), + _Checkpoint(1643493960, 1430000), + _Checkpoint(1644093045, 1440000), + _Checkpoint(1644691833, 1450000), + _Checkpoint(1645291245, 1460000), + _Checkpoint(1645892190, 1470000), + _Checkpoint(1646489895, 1480000), + _Checkpoint(1647089648, 1490000), + _Checkpoint(1647694665, 1500000), + _Checkpoint(1648293585, 1510000), + _Checkpoint(1648893525, 1520000), + _Checkpoint(1649497306, 1530000), + _Checkpoint(1650098656, 1540000), + _Checkpoint(1650694980, 1550000), + _Checkpoint(1651303650, 1560000), + _Checkpoint(1651899285, 1570000), + _Checkpoint(1652501596, 1580000), + _Checkpoint(1653101220, 1590000), + _Checkpoint(1653700166, 1600000), + _Checkpoint(1654302094, 1610000), + _Checkpoint(1654906575, 1620000), + _Checkpoint(1655510644, 1630000), + _Checkpoint(1656108615, 1640000), + _Checkpoint(1656712545, 1650000), + _Checkpoint(1657313460, 1660000), + _Checkpoint(1657911515, 1670000), + _Checkpoint(1658515717, 1680000), + _Checkpoint(1659121230, 1690000), + _Checkpoint(1659722213, 1700000), + _Checkpoint(1660318875, 1710000), + _Checkpoint(1660921522, 1720000), + _Checkpoint(1661518436, 1730000), + _Checkpoint(1662118050, 1740000), + _Checkpoint(1662717982, 1750000), + _Checkpoint(1663306425, 1760000), + _Checkpoint(1663904520, 1770000), + _Checkpoint(1664511195, 1780000), + _Checkpoint(1665113460, 1790000), + _Checkpoint(1665705148, 1800000), + _Checkpoint(1666306807, 1810000), + _Checkpoint(1666909050, 1820000), + _Checkpoint(1667510577, 1830000), + _Checkpoint(1668111697, 1840000), + _Checkpoint(1668711150, 1850000), + _Checkpoint(1669309785, 1860000), + _Checkpoint(1669910715, 1870000), + _Checkpoint(1670511885, 1880000), + _Checkpoint(1671111596, 1890000), + _Checkpoint(1671713348, 1900000), + _Checkpoint(1672312933, 1910000), + _Checkpoint(1672913610, 1920000), + _Checkpoint(1673517614, 1930000), + _Checkpoint(1674116655, 1940000), + _Checkpoint(1674717105, 1950000), + _Checkpoint(1675316550, 1960000), + _Checkpoint(1675914240, 1970000), + _Checkpoint(1676519608, 1980000), + _Checkpoint(1677113500, 1990000), + _Checkpoint(1677715095, 2000000), + _Checkpoint(1678316835, 2010000), + _Checkpoint(1678912224, 2020000), + _Checkpoint(1679513175, 2030000), + _Checkpoint(1680112070, 2040000), + _Checkpoint(1680711218, 2050000), + _Checkpoint(1681313478, 2060000), + _Checkpoint(1681909155, 2070000), + _Checkpoint(1682507671, 2080000), + _Checkpoint(1683107382, 2090000), + _Checkpoint(1683712020, 2100000), + _Checkpoint(1684311975, 2110000), + _Checkpoint(1684915377, 2120000), + _Checkpoint(1685514352, 2130000), + _Checkpoint(1686112770, 2140000), + _Checkpoint(1686710430, 2150000), + _Checkpoint(1687309584, 2160000), + _Checkpoint(1687916053, 2170000), + _Checkpoint(1688521450, 2180000), + _Checkpoint(1689118965, 2190000), + _Checkpoint(1689719584, 2200000), + _Checkpoint(1690321515, 2210000), + _Checkpoint(1690920915, 2220000), + _Checkpoint(1691524920, 2230000), + _Checkpoint(1692120135, 2240000), + _Checkpoint(1692715440, 2250000), + _Checkpoint(1693313578, 2260000), + _Checkpoint(1693915410, 2270000), + _Checkpoint(1694516824, 2280000), + _Checkpoint(1695114075, 2290000), + _Checkpoint(1695712485, 2300000), + _Checkpoint(1696314266, 2310000), + _Checkpoint(1696913190, 2320000), + _Checkpoint(1697513447, 2330000), + _Checkpoint(1698115590, 2340000), + _Checkpoint(1698715860, 2350000), + _Checkpoint(1699318665, 2360000), + _Checkpoint(1699918515, 2370000), + _Checkpoint(1700510340, 2380000), + _Checkpoint(1701107490, 2390000), + _Checkpoint(1701715953, 2400000), + _Checkpoint(1702319655, 2410000), + _Checkpoint(1702921425, 2420000), + _Checkpoint(1703518740, 2430000), + _Checkpoint(1704117450, 2440000), + _Checkpoint(1704715350, 2450000), + _Checkpoint(1705314150, 2460000), + _Checkpoint(1705911585, 2470000), + _Checkpoint(1706513190, 2480000), + _Checkpoint(1707111871, 2490000), + _Checkpoint(1707712515, 2500000), + _Checkpoint(1708316785, 2510000), + _Checkpoint(1708917275, 2520000), + _Checkpoint(1709515140, 2530000), + _Checkpoint(1710115320, 2540000), + _Checkpoint(1710718811, 2550000), + _Checkpoint(1711340233, 2560000), + _Checkpoint(1711937827, 2570000), + _Checkpoint(1712536797, 2580000), + _Checkpoint(1713132840, 2590000), + _Checkpoint(1713732780, 2600000), + _Checkpoint(1714330320, 2610000), + _Checkpoint(1714933845, 2620000), + _Checkpoint(1715536185, 2630000), + _Checkpoint(1716146082, 2640000), + _Checkpoint(1716742155, 2650000), + _Checkpoint(1717343205, 2660000), + _Checkpoint(1717937699, 2670000), + _Checkpoint(1718535495, 2680000), + _Checkpoint(1719141615, 2690000), + _Checkpoint(1719744075, 2700000), + _Checkpoint(1720336724, 2710000), + _Checkpoint(1720941803, 2720000), + _Checkpoint(1721539733, 2730000), + _Checkpoint(1722139174, 2740000), + _Checkpoint(1722737769, 2750000), + _Checkpoint(1723336755, 2760000), + _Checkpoint(1723937074, 2770000), + _Checkpoint(1724533860, 2780000), + _Checkpoint(1725126437, 2790000), + _Checkpoint(1725728340, 2800000), + _Checkpoint(1726330290, 2810000), + _Checkpoint(1726931550, 2820000), + _Checkpoint(1727531335, 2830000), + _Checkpoint(1728132893, 2840000), + _Checkpoint(1728731641, 2850000), + _Checkpoint(1729328707, 2860000), + _Checkpoint(1729927125, 2870000), + _Checkpoint(1730525159, 2880000), + _Checkpoint(1731124123, 2890000), + _Checkpoint(1731728397, 2900000), + _Checkpoint(1732328405, 2910000), + _Checkpoint(1732929444, 2920000), + _Checkpoint(1733527918, 2930000), + _Checkpoint(1734125775, 2940000), + _Checkpoint(1734721755, 2950000), + _Checkpoint(1735326599, 2960000), + _Checkpoint(1735919505, 2970000), + _Checkpoint(1736520114, 2980000), + _Checkpoint(1737119579, 2990000), + _Checkpoint(1737724515, 3000000), + _Checkpoint(1738328220, 3010000), + _Checkpoint(1738929119, 3020000), + _Checkpoint(1739527564, 3030000), + _Checkpoint(1740125219, 3040000), + _Checkpoint(1740726039, 3050000), + _Checkpoint(1741327110, 3060000), + _Checkpoint(1741927857, 3070000), + _Checkpoint(1742530920, 3080000), + _Checkpoint(1743149987, 3090000), + _Checkpoint(1743747268, 3100000), + _Checkpoint(1744349415, 3110000), + _Checkpoint(1744944112, 3120000), + _Checkpoint(1745543580, 3130000), + _Checkpoint(1746142732, 3140000), + _Checkpoint(1746742705, 3150000), + _Checkpoint(1747344191, 3160000), + _Checkpoint(1747946610, 3170000), + _Checkpoint(1748545387, 3180000), + _Checkpoint(1749144165, 3190000), + _Checkpoint(1749742950, 3200000), + _Checkpoint(1750343363, 3210000), + _Checkpoint(1750946445, 3220000), + _Checkpoint(1751545747, 3230000), + _Checkpoint(1752144620, 3240000), + _Checkpoint(1752746280, 3250000), + _Checkpoint(1753343664, 3260000), + _Checkpoint(1753948349, 3270000), + _Checkpoint(1754547975, 3280000), + _Checkpoint(1755145610, 3290000), + _Checkpoint(1755744210, 3300000), + _Checkpoint(1756341045, 3310000), + _Checkpoint(1756940460, 3320000), + _Checkpoint(1757537565, 3330000), + _Checkpoint(1758141330, 3340000), + _Checkpoint(1758742563, 3350000), + _Checkpoint(1759340190, 3360000), + _Checkpoint(1759941840, 3370000), + _Checkpoint(1760542420, 3380000), + _Checkpoint(1761144358, 3390000), + _Checkpoint(1761745435, 3400000), + _Checkpoint(1762345095, 3410000), + _Checkpoint(1762942865, 3420000), + _Checkpoint(1763540460, 3430000), + _Checkpoint(1764144321, 3440000), + _Checkpoint(1764745065, 3450000), + _Checkpoint(1765347169, 3460000), + _Checkpoint(1765944370, 3470000), + _Checkpoint(1766548020, 3480000), + _Checkpoint(1767144555, 3490000), + _Checkpoint(1767748830, 3500000), + _Checkpoint(1768350722, 3510000), + _Checkpoint(1768945425, 3520000), + _Checkpoint(1769545406, 3530000), + _Checkpoint(1770144700, 3540000), + _Checkpoint(1770745380, 3550000), + _Checkpoint(1771345176, 3560000), + _Checkpoint(1771943526, 3570000), + _Checkpoint(1772545646, 3580000), + _Checkpoint(1773146830, 3590000), + _Checkpoint(1773749868, 3600000), + _Checkpoint(1774347077, 3610000), + _Checkpoint(1774950120, 3620000), + _Checkpoint(1775548635, 3630000), + _Checkpoint(1776148320, 3640000), + _Checkpoint(1776750266, 3650000), + _Checkpoint(1777351110, 3660000), + _Checkpoint(1777953826, 3670000), + _Checkpoint(1778551170, 3680000), + _Checkpoint(1779153960, 3690000), + _Checkpoint(1779758055, 3700000), + _Checkpoint(1780362465, 3710000), + _Checkpoint(1780966500, 3720000), + _Checkpoint(1781563275, 3730000), + _Checkpoint(1782174166, 3740000), + _Checkpoint(1782775815, 3750000), + _Checkpoint(1783378725, 3760000), + _Checkpoint(1783971435, 3770000), + _Checkpoint(1784575305, 3780000), + _Checkpoint(1785177870, 3790000), + _Checkpoint(1785774750, 3800000), + _Checkpoint(1786377455, 3810000), + _Checkpoint(1786978902, 3820000), + ]; + + static int getBlockHeightByTime(DateTime time) { + final t = time.toUtc().millisecondsSinceEpoch; + + if (_points.isEmpty) return 0; + + if (t <= _points.first.timeMs) { + return 1; + } + + for (int i = 0; i < _points.length - 1; i++) { + final p0 = _points[i]; + final p1 = _points[i + 1]; + + if (t >= p0.timeMs && t < p1.timeMs) { + return _interpolate( + p0.height, + p1.height, + p0.timeMs, + p1.timeMs, + t, + ); + } + } + + final last = _points[_points.length - 1]; + final prev = _points[_points.length - 2]; + + final avgBlockTimeMs = (last.timeMs - prev.timeMs) / (last.height - prev.height); + + final blocksSinceLast = ((t - last.timeMs) / avgBlockTimeMs).floor(); + + return last.height + blocksSinceLast; + } + + static DateTime getTimeByBlockHeight(int height) { + if (_points.isEmpty) return DateTime.fromMillisecondsSinceEpoch(0, isUtc: true); + if (height <= 1) { + return DateTime.fromMillisecondsSinceEpoch(_points.first.timeMs, isUtc: true); + } + + for (int i = 0; i < _points.length - 1; i++) { + final p0 = _points[i]; + final p1 = _points[i + 1]; + if (height >= p0.height && height < p1.height) { + final t = _interpolate( + p0.timeMs, + p1.timeMs, + p0.height, + p1.height, + height, + ); + return DateTime.fromMillisecondsSinceEpoch(t, isUtc: true); + } + } + + final last = _points[_points.length - 1]; + final prev = _points[_points.length - 2]; + final avgBlockTimeMs = (last.timeMs - prev.timeMs) / (last.height - prev.height); + final msSinceLast = ((height - last.height) * avgBlockTimeMs).floor(); + return DateTime.fromMillisecondsSinceEpoch(last.timeMs + msSinceLast, isUtc: true); + } + + static int _interpolate( + int h0, + int h1, + int t0, + int t1, + int t, + ) { + final ratio = (t - t0) / (t1 - t0); + return h0 + ((h1 - h0) * ratio).floor(); + } +} + +class _Checkpoint { + final int timeMs; + final int height; + + _Checkpoint(int timeSec, this.height) : timeMs = timeSec * 1000; +} diff --git a/cw_zano/lib/zano_utils.dart b/cw_zano/lib/zano_utils.dart index f39f20462..72b07b72f 100644 --- a/cw_zano/lib/zano_utils.dart +++ b/cw_zano/lib/zano_utils.dart @@ -1,9 +1,18 @@ import 'dart:convert'; -import 'package:monero/zano.dart' as zano; import 'package:cw_zano/api/model/get_address_info_result.dart'; +import 'package:cw_zano/get_height_by_date.dart'; +import 'package:monero/zano.dart' as zano; class ZanoUtils { + static int heightByDate(DateTime date) => + ZanoHeight.getBlockHeightByTime(date.toUtc().subtract(const Duration(days: 1))); + + static int creationTimestampFromHeight(int height) { + if (height <= 0) return 0; + return ZanoHeight.getTimeByBlockHeight(height).millisecondsSinceEpoch ~/ 1000; + } + static bool validateAddress(String address) { try { final result = GetAddressInfoResult.fromJson( diff --git a/cw_zano/lib/zano_wallet.dart b/cw_zano/lib/zano_wallet.dart index 8b45b142a..df5ceff70 100644 --- a/cw_zano/lib/zano_wallet.dart +++ b/cw_zano/lib/zano_wallet.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:core'; import 'dart:io'; import 'dart:math'; @@ -6,6 +7,7 @@ import 'dart:math'; import 'package:cw_core/amount/money.dart'; import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pending_transaction.dart'; @@ -15,6 +17,7 @@ import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wallet_keys_file.dart'; import 'package:cw_core/zano_asset.dart'; import 'package:cw_zano/api/model/create_wallet_result.dart'; import 'package:cw_zano/api/model/destination.dart'; @@ -32,7 +35,10 @@ import 'package:cw_zano/zano_wallet_addresses.dart'; import 'package:cw_zano/zano_wallet_api.dart'; import 'package:cw_zano/zano_wallet_exceptions.dart'; import 'package:cw_zano/zano_wallet_service.dart'; +import 'package:cw_zano/zano_utils.dart'; import 'package:cw_zano/api/model/balance.dart'; +import 'package:cw_zano/bip39_seed.dart'; +import 'package:path/path.dart' as p; import 'package:mobx/mobx.dart'; @@ -42,10 +48,12 @@ class ZanoWallet = ZanoWalletBase with _$ZanoWallet; abstract class ZanoWalletBase extends WalletBase - with Store, ZanoWalletApi { + with Store, ZanoWalletApi, WalletKeysFile { static const int _autoSaveIntervalSeconds = 30; static const int _pollIntervalMilliseconds = 5000; static const int _maxLoadAssetsRetries = 5; + static const int _walletStateReady = 2; + static const String _cakeKeysFileSuffix = '.cw.keys'; @override void setPassword(String password) { @@ -54,10 +62,23 @@ abstract class ZanoWalletBase } String _password; + final EncryptionFileUtils _encryptionFileUtils; + bool _didSyncSecrets = false; @override String get password => _password; + @override + Future makeKeysFilePath() async => "${await makePath()}$_cakeKeysFileSuffix"; + + @override + WalletKeysData get walletKeysData => WalletKeysData( + mnemonic: _hasSeed ? seed : null, + passphrase: (passphrase ?? '').isEmpty ? null : passphrase, + ); + + bool get _hasSeed => seed.trim().isNotEmpty; + @override Future signMessage(String message, {String? address = null}) => super.signMessage(message, address: address); @@ -105,7 +126,8 @@ abstract class ZanoWalletBase /// number of transactions in each request static final int _txChunkSize = (pow(2, 32) - 1).toInt(); - ZanoWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password) + ZanoWalletBase(WalletInfo walletInfo, DerivationInfo derivationInfo, String password, + this._encryptionFileUtils) : balance = ObservableMap.of({CryptoCurrency.zano: ZanoBalance.empty(CryptoCurrency.zano)}), _isTransactionUpdating = false, _hasSyncAfterStartup = false, @@ -126,74 +148,138 @@ abstract class ZanoWalletBase @override Future changePassword(String password) async { setPassword(password); + if (_hasSeed) { + await saveKeysFile(_password, _encryptionFileUtils); + saveKeysFile(_password, _encryptionFileUtils, true); + } } - static Future create({required WalletCredentials credentials}) async { + static Future create({ + required WalletCredentials credentials, + required EncryptionFileUtils encryptionFileUtils, + }) async { final wallet = ZanoWallet(credentials.walletInfo!, - await credentials.walletInfo!.getDerivationInfo(), credentials.password!); + await credentials.walletInfo!.getDerivationInfo(), credentials.password!, encryptionFileUtils); await wallet.initWallet(); final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type); - final createWalletResult = await wallet.createWallet(path, credentials.password!); + final strength = credentials.seedPhraseLength == 24 ? 256 : 128; + final providedMnemonic = + credentials is ZanoNewWalletCredentials ? credentials.mnemonic : null; + final mnemonic = providedMnemonic ?? generateBip39Mnemonic(strength: strength); + final passphrase = credentials.passphrase ?? ''; + final secretDerivation = getSecretDerivationFromBip39(mnemonic, passphrase: passphrase); + final creationTimestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; + final createWalletResult = await wallet.restoreWalletFromDerivations( + path, + credentials.password!, + secretDerivation, + creationTimestamp: creationTimestamp, + ); await wallet.initWallet(); + wallet.seed = mnemonic; + wallet.passphrase = passphrase; await wallet.parseCreateWalletResult(createWalletResult); - if (credentials.passphrase != null) { - await wallet.setPassphrase(credentials.passphrase!); - wallet.seed = await createWalletResult.seed(wallet); - wallet.passphrase = await wallet.getPassphrase(); - } + await wallet._syncSecretsAndDerivation(); await wallet.init(createWalletResult.wi.address); + await wallet.save(); return wallet; } - static Future restore( - {required ZanoRestoreWalletFromSeedCredentials credentials}) async { + static Future restore({ + required ZanoRestoreWalletFromSeedCredentials credentials, + required EncryptionFileUtils encryptionFileUtils, + }) async { final wallet = ZanoWallet(credentials.walletInfo!, - await credentials.walletInfo!.getDerivationInfo(), credentials.password!); + await credentials.walletInfo!.getDerivationInfo(), credentials.password!, encryptionFileUtils); await wallet.initWallet(); final path = await pathForWallet(name: credentials.name, type: credentials.walletInfo!.type); - final createWalletResult = await wallet.restoreWalletFromSeed( - path, credentials.password!, credentials.mnemonic, credentials.passphrase); - await wallet.initWallet(); - await wallet.parseCreateWalletResult(createWalletResult); - if (credentials.passphrase != null) { - await wallet.setPassphrase(credentials.passphrase!); - wallet.seed = await createWalletResult.seed(wallet); - wallet.passphrase = await wallet.getPassphrase(); + final passphrase = credentials.passphrase ?? ''; + final CreateWalletResult createWalletResult; + final isBip39 = isBip39Seed(credentials.mnemonic); + final creationTimestamp = ZanoUtils.creationTimestampFromHeight(credentials.height ?? 0); + if (isBip39) { + final secretDerivation = + getSecretDerivationFromBip39(credentials.mnemonic, passphrase: passphrase); + createWalletResult = await wallet.restoreWalletFromDerivations( + path, + credentials.password!, + secretDerivation, + creationTimestamp: creationTimestamp, + ); + } else { + createWalletResult = await wallet.restoreWalletFromSeed( + path, + credentials.password!, + credentials.mnemonic, + credentials.passphrase, + creationTimestamp: creationTimestamp, + ); } + await wallet.initWallet(); + wallet.seed = credentials.mnemonic; + wallet.passphrase = passphrase; + await wallet.parseCreateWalletResult(createWalletResult); + if (!isBip39) { + try { + if (passphrase.isNotEmpty) { + await wallet.setPassphrase(passphrase); + } + final nativeSeed = await createWalletResult.seed(wallet); + if (nativeSeed.isNotEmpty) { + wallet.seed = nativeSeed; + } + } catch (e) { + printV('native seed not available yet: $e'); + } + } + await wallet._syncSecretsAndDerivation(); await wallet.init(createWalletResult.wi.address); + await wallet.save(); return wallet; } static Future open( - {required String name, required String password, required WalletInfo walletInfo}) async { + {required String name, + required String password, + required WalletInfo walletInfo, + required EncryptionFileUtils encryptionFileUtils}) async { final path = await pathForWallet(name: name, type: walletInfo.type); + final wallet = + ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password, encryptionFileUtils); + + await wallet._loadKeysFileIfPresent(); + + late final CreateWalletResult createWalletResult; if (ZanoWalletApi.openWalletCache[path] != null) { - final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password); - await wallet.parseCreateWalletResult(ZanoWalletApi.openWalletCache[path]!).then((_) { - unawaited(wallet.init(ZanoWalletApi.openWalletCache[path]!.wi.address)); - }); - return wallet; + createWalletResult = ZanoWalletApi.openWalletCache[path]!; } else { - final wallet = ZanoWallet(walletInfo, await walletInfo.getDerivationInfo(), password); await wallet.initWallet(); - final createWalletResult = await wallet.loadWallet(path, password); - await wallet.parseCreateWalletResult(createWalletResult).then((_) { - unawaited(wallet.init(createWalletResult.wi.address)); - }); - return wallet; + createWalletResult = await wallet.loadWallet(path, password); } + await wallet.parseCreateWalletResult(createWalletResult); + if (!wallet._hasSeed) { + await wallet._loadSeedIfAvailable(); + } + await wallet._syncSecretsAndDerivation(); + unawaited(wallet.init(createWalletResult.wi.address)); + return wallet; } Future parseCreateWalletResult(CreateWalletResult result) async { hWallet = result.walletId; - seed = await result.seed(this); keys = ZanoWalletKeys( privateSpendKey: result.privateSpendKey, privateViewKey: result.privateViewKey, publicSpendKey: result.publicSpendKey, publicViewKey: result.publicViewKey, ); - passphrase = await getPassphrase(); + if ((passphrase ?? '').isEmpty) { + try { + passphrase = await getPassphrase(); + } catch (e) { + printV('passphrase not available yet: $e'); + } + } printV('setting hWallet = ${result.walletId}'); walletAddresses.address = result.wi.address; @@ -214,6 +300,126 @@ abstract class ZanoWalletBase } } + bool _isWalletReady(GetWalletStatusResult walletStatus) => + !walletStatus.isInLongRefresh && walletStatus.walletState == _walletStateReady; + + Future _hasKeysFile() async { + try { + final path = await makeKeysFilePath(); + return File(path).existsSync() || File('$path.backup').existsSync(); + } catch (_) { + return false; + } + } + + Future _loadKeysFileIfPresent() async { + if (!await _hasKeysFile()) { + return; + } + final path = await makeKeysFilePath(); + Future read(String readPath) async { + final jsonSource = await _encryptionFileUtils.read(path: readPath, password: _password); + return WalletKeysData.fromJSON(json.decode(jsonSource) as Map); + } + + try { + WalletKeysData keysData; + if (File(path).existsSync()) { + keysData = await read(path); + } else { + keysData = await read('$path.backup'); + await saveKeysFile(_password, _encryptionFileUtils); + } + if (keysData.mnemonic != null && keysData.mnemonic!.trim().isNotEmpty) { + seed = keysData.mnemonic!; + } + if (keysData.passphrase != null && keysData.passphrase!.isNotEmpty) { + passphrase = keysData.passphrase; + } + } catch (e) { + printV('error reading zano keys file $e'); + } + } + + Future _saveKeysFileIfNeeded() async { + if (!_hasSeed || await _hasKeysFile()) { + return; + } + await saveKeysFile(_password, _encryptionFileUtils); + saveKeysFile(_password, _encryptionFileUtils, true); + } + + Future _loadSeedIfAvailable() async { + if (!isBip39Seed(seed)) { + try { + final loaded = await getSeed(); + if (loaded.isNotEmpty) { + seed = loaded; + } + } catch (e) { + printV('seed not available yet: $e'); + } + } + if ((passphrase ?? '').isEmpty) { + try { + passphrase = await getPassphrase() ?? passphrase; + } catch (e) { + printV('passphrase not available yet: $e'); + } + } + } + + Future _syncSecretsAndDerivation() async { + if (!_hasSeed || _didSyncSecrets) { + return; + } + try { + await _persistSecretsIfNeeded(); + await _setDerivationForSeed(); + await _saveKeysFileIfNeeded(); + _didSyncSecrets = true; + } catch (e) { + printV('error persisting zano secrets $e'); + } + } + + Future _persistSecretsIfNeeded() async { + if (isBip39Seed(seed) && await getBip39Mnemonic() == null) { + await setBip39Secrets( + mnemonic: seed, + creationTimestamp: walletInfo.restoreHeight > 0 + ? ZanoUtils.creationTimestampFromHeight(walletInfo.restoreHeight) + : DateTime.now().millisecondsSinceEpoch ~/ 1000, + ); + } + if ((passphrase ?? '').isNotEmpty && await getPassphrase() == null) { + await setPassphrase(passphrase!); + } + } + + Future _setDerivationForSeed() async { + if (!_hasSeed) { + return; + } + final di = await walletInfo.getDerivationInfo(); + if (isBip39Seed(seed)) { + if (di.derivationType == DerivationType.bip39 && + (di.derivationPath ?? '').isNotEmpty) { + return; + } + di.derivationType = DerivationType.bip39; + di.derivationPath = "m/44'/128'/0'/0/0"; + await di.save(); + return; + } + if (di.derivationType != DerivationType.bip39 && di.derivationPath == 'legacy') { + return; + } + di.derivationType = DerivationType.unknown; + di.derivationPath = 'legacy'; + await di.save(); + } + @override Future close({bool shouldCleanup = true}) async { closeWallet(null); @@ -310,12 +516,13 @@ abstract class ZanoWalletBase Future> fetchTransactions() async { try { final transfers = []; + var offset = 0; late GetRecentTxsAndInfoResult result; do { - result = await getRecentTxsAndInfo(offset: 0, count: _txChunkSize); - // _lastTxIndex += result.transfers.length; + result = await getRecentTxsAndInfo(offset: offset, count: _txChunkSize); transfers.addAll(result.transfers); - } while (result.lastItemIndex + 1 < result.totalTransfers); + offset = result.lastItemIndex + 1; + } while (offset < result.totalTransfers); return Transfer.makeMap(transfers, zanoAssets, currentDaemonHeight); } catch (e) { printV((e.toString())); @@ -334,12 +541,18 @@ abstract class ZanoWalletBase @override Future renameWalletFiles(String newWalletName) async { - final currentWalletPath = await pathForWallet(name: name, type: type); + final currentWalletDirPath = await pathForWalletDir(name: name, type: type); + final currentWalletPath = '$currentWalletDirPath/$name'; final currentCacheFile = File(currentWalletPath); final currentKeysFile = File('$currentWalletPath.keys'); final currentAddressListFile = File('$currentWalletPath.address.txt'); + final currentPendingKiFile = File('$currentWalletPath.outkey2ki'); + final currentSecretsFile = File(p.join(currentWalletDirPath, 'zano-secrets.json.bin')); + final currentCakeKeysFile = File('$currentWalletPath$_cakeKeysFileSuffix'); + final currentCakeKeysBackupFile = File('$currentWalletPath$_cakeKeysFileSuffix.backup'); - final newWalletPath = await pathForWallet(name: newWalletName, type: type); + final newWalletDirPath = await pathForWalletDir(name: newWalletName, type: type); + final newWalletPath = '$newWalletDirPath/$newWalletName'; // Copies current wallet files into new wallet name's dir and files if (currentCacheFile.existsSync()) { @@ -351,9 +564,22 @@ abstract class ZanoWalletBase if (currentAddressListFile.existsSync()) { await currentAddressListFile.copy('$newWalletPath.address.txt'); } + if (currentPendingKiFile.existsSync()) { + await currentPendingKiFile.copy('$newWalletPath.outkey2ki'); + } + if (currentSecretsFile.existsSync()) { + await currentSecretsFile.copy(p.join(newWalletDirPath, 'zano-secrets.json.bin')); + } + if (currentCakeKeysFile.existsSync()) { + await currentCakeKeysFile.copy('$newWalletPath$_cakeKeysFileSuffix'); + } + if (currentCakeKeysBackupFile.existsSync()) { + await currentCakeKeysBackupFile.copy('$newWalletPath$_cakeKeysFileSuffix.backup'); + } - // Delete old name's dir and files - await Directory(currentWalletPath).delete(recursive: true); + // Delete the old wallet *directory*. pathForWallet() is the wallet file + // (...//); Directory(filePath).delete leaves seed sidecars. + await Directory(currentWalletDirPath).delete(recursive: true); } @override @@ -362,6 +588,7 @@ abstract class ZanoWalletBase @override Future save() async { try { + await _saveKeysFileIfNeeded(); await store(); await walletAddresses.updateAddressesInBox(); } catch (e) { @@ -544,9 +771,12 @@ abstract class ZanoWalletBase _updateSyncProgress(walletStatus); // we can call getWalletInfo ONLY if getWalletStatus returns NOT is in long refresh and wallet state is 2 (ready) - if (!walletStatus.isInLongRefresh && walletStatus.walletState == 2) { + if (_isWalletReady(walletStatus)) { + if (!_hasSeed) { + await _loadSeedIfAvailable(); + } + await _syncSecretsAndDerivation(); final walletInfo = await getWalletInfo(); - seed = await walletInfo.wiExtended.seed(this); keys = ZanoWalletKeys( privateSpendKey: walletInfo.wiExtended.spendPrivateKey, privateViewKey: walletInfo.wiExtended.viewPrivateKey, diff --git a/cw_zano/lib/zano_wallet_api.dart b/cw_zano/lib/zano_wallet_api.dart index cec26ed55..7196c1d94 100644 --- a/cw_zano/lib/zano_wallet_api.dart +++ b/cw_zano/lib/zano_wallet_api.dart @@ -46,12 +46,13 @@ mixin ZanoWalletApi { void setPassword(String password) => zano.PlainWallet_resetWalletPassword(hWallet, password); - void closeWallet(int? walletToClose, {bool force = false}) async { + Future closeWallet(int? walletToClose, {bool force = false}) async { printV('close_wallet ${walletToClose ?? hWallet}: $force'); if (Platform.isWindows || force) { - final result = await _closeWallet(walletToClose ?? hWallet); + final id = walletToClose ?? hWallet; + final result = await _closeWallet(id); printV('close_wallet result $result'); - openWalletCache.removeWhere((_, cwr) => cwr.walletId == (walletToClose ?? hWallet)); + openWalletCache.removeWhere((_, cwr) => cwr.walletId == id); } } @@ -76,31 +77,34 @@ mixin ZanoWalletApi { Future _getWalletSecretsFile() async { final dir = await getWalletDir(); - final file = File(p.join(dir.path, "zano-secrets.json.bin")); - return file; + return File(p.join(dir.path, 'zano-secrets.json.bin')); } Future> _getSecrets() async { - final file = await _getWalletSecretsFile(); - if (!file.existsSync()) { + try { + final file = await _getWalletSecretsFile(); + if (!file.existsSync()) { + return {}; + } + final data = file.readAsBytesSync(); + final b64 = convert.base64.encode(data); + final respStr = await invokeMethod('decrypt_data', {'buff': b64}); + final resp = convert.json.decode(respStr); + final dataBytes = convert.base64.decode(resp['result']['res_buff'] as String); + final dataStr = convert.utf8.decode(dataBytes); + return convert.json.decode(dataStr) as Map; + } catch (e) { + printV('error reading zano secrets $e'); return {}; } - final data = file.readAsBytesSync(); - final b64 = convert.base64.encode(data); - final respStr = await invokeMethod("decrypt_data", {"buff": "$b64"}); - final resp = convert.json.decode(respStr); - final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); - final dataStr = convert.utf8.decode(dataBytes); - final dataObject = convert.json.decode(dataStr); - return dataObject as Map; } Future _setSecrets(Map data) async { final dataStr = convert.json.encode(data); final b64 = convert.base64.encode(convert.utf8.encode(dataStr)); - final respStr = await invokeMethod("encrypt_data", {"buff": "$b64"}); + final respStr = await invokeMethod('encrypt_data', {'buff': b64}); final resp = convert.json.decode(respStr); - final dataBytes = convert.base64.decode(resp["result"]["res_buff"] as String); + final dataBytes = convert.base64.decode(resp['result']['res_buff'] as String); final file = await _getWalletSecretsFile(); file.writeAsBytesSync(dataBytes); } @@ -124,7 +128,25 @@ mixin ZanoWalletApi { return _setWalletSecret("passphrase", passphrase); } + Future getBip39Mnemonic() async { + return await _getWalletSecret("bip39_mnemonic"); + } + + Future setBip39Secrets({ + required String mnemonic, + required int creationTimestamp, + }) async { + final secrets = await _getSecrets(); + secrets["bip39_mnemonic"] = mnemonic; + secrets["creation_timestamp"] = creationTimestamp.toString(); + await _setSecrets(secrets); + } + Future getSeed() async { + final bip39Mnemonic = await getBip39Mnemonic(); + if (bip39Mnemonic != null && bip39Mnemonic.isNotEmpty) { + return bip39Mnemonic; + } final passphrase = await getPassphrase(); final respStr = await invokeMethod("get_restore_info", {"seed_password": passphrase ?? ""}); final resp = convert.json.decode(respStr); @@ -328,10 +350,59 @@ mixin ZanoWalletApi { return result; } + Future restoreWalletFromDerivations( + String path, + String password, + String secretDerivation, { + bool isAuditable = false, + required int creationTimestamp, + }) async { + printV('restore_wallet_from_derivations path $path'); + final params = jsonEncode({ + "creation_timestamp": creationTimestamp, + "is_auditable": isAuditable, + "pass": password, + "path": path, + "secret_derivation": secretDerivation, + }); + final json = await callSyncMethod('restore_from_derivations', 0, params); + final map = jsonDecode(json) as Map?; + if (map?['error'] != null) { + final code = map!['error']!['code'] ?? ''; + final message = map['error']!['message'] ?? ''; + if (code == Consts.errorWrongSeed) { + throw RestoreFromSeedsException( + 'Error restoring wallet\nPlease check the seed words are correct. Additionally, if you created this wallet with a passphrase please add it under the Advanced Settings page.'); + } else if (code == Consts.errorAlreadyExists) { + throw RestoreFromSeedsException('Error restoring wallet, already exists'); + } + throw RestoreFromSeedsException('Error restoring wallet, $message ($code)'); + } + if (map?['result'] == null) { + throw RestoreFromSeedsException('Error restoring wallet, empty response'); + } + final result = CreateWalletResult.fromJson(map!['result'] as Map); + openWalletCache[path] = result; + printV('restore_wallet_from_derivations ${result.name} ${result.wi.address}'); + return result; + } + Future restoreWalletFromSeed( - String path, String password, String seed, String? passphrase) async { + String path, + String password, + String seed, + String? passphrase, { + required int creationTimestamp, + }) async { printV('restore_wallet path $path'); - final json = zano.PlainWallet_restore(seed, path, password, passphrase ?? ''); + final params = jsonEncode({ + "creation_timestamp": creationTimestamp, + "pass": password, + "path": path, + "seed_phrase": seed, + "seed_pass": passphrase ?? '', + }); + final json = await callSyncMethod('restore', 0, params); final map = jsonDecode(json) as Map?; if (map?['error'] != null) { final code = map!['error']!['code'] ?? ''; diff --git a/cw_zano/lib/zano_wallet_service.dart b/cw_zano/lib/zano_wallet_service.dart index 9a33bc34e..cf50509f5 100644 --- a/cw_zano/lib/zano_wallet_service.dart +++ b/cw_zano/lib/zano_wallet_service.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:collection/collection.dart'; +import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; @@ -14,8 +15,14 @@ import 'package:hive/hive.dart'; import 'package:monero/zano.dart' as zano; class ZanoNewWalletCredentials extends WalletCredentials { - ZanoNewWalletCredentials({required String name, String? password, required String? passphrase}) - : super(name: name, password: password, passphrase: passphrase); + ZanoNewWalletCredentials({ + required String name, + String? password, + required String? passphrase, + this.mnemonic, + }) : super(name: name, password: password, passphrase: passphrase); + + final String? mnemonic; } class ZanoRestoreWalletFromSeedCredentials extends WalletCredentials { @@ -52,7 +59,9 @@ class ZanoWalletService extends WalletService< ZanoRestoreWalletFromSeedCredentials, ZanoRestoreWalletFromKeysCredentials, ZanoNewWalletCredentials> { - ZanoWalletService(); + ZanoWalletService(this.isDirect); + + final bool isDirect; static bool walletFilesExist(String path) => !File(path).existsSync() && !File('$path.keys').existsSync(); @@ -65,7 +74,8 @@ class ZanoWalletService extends WalletService< @override Future create(WalletCredentials credentials, {bool? isTestnet}) async { printV('zanowallet service create isTestnet $isTestnet'); - return await ZanoWalletBase.create(credentials: credentials); + return await ZanoWalletBase.create( + credentials: credentials, encryptionFileUtils: encryptionFileUtilsFor(isDirect)); } @override @@ -82,12 +92,21 @@ class ZanoWalletService extends WalletService< } try { final wallet = - await ZanoWalletBase.open(name: name, password: password, walletInfo: walletInfo); + await ZanoWalletBase.open( + name: name, + password: password, + walletInfo: walletInfo, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); saveBackup(name); return wallet; } catch (e) { + printV('openWallet $name failed: $e'); await restoreWalletFilesFromBackup(name); - return await ZanoWalletBase.open(name: name, password: password, walletInfo: walletInfo); + return await ZanoWalletBase.open( + name: name, + password: password, + walletInfo: walletInfo, + encryptionFileUtils: encryptionFileUtilsFor(isDirect)); } } @@ -115,15 +134,24 @@ class ZanoWalletService extends WalletService< throw Exception('Wallet not found'); } final currentWallet = - ZanoWallet(currentWalletInfo, await currentWalletInfo.getDerivationInfo(), password); + ZanoWallet(currentWalletInfo, await currentWalletInfo.getDerivationInfo(), password, + encryptionFileUtilsFor(isDirect)); + + final oldPath = await pathForWallet(name: currentName, type: getType()); + final cached = ZanoWalletApi.openWalletCache.remove(oldPath); + if (cached != null) { + currentWallet.hWallet = cached.walletId; + await currentWallet.closeWallet(cached.walletId, force: true); + } await currentWallet.renameWalletFiles(newName); - final newWalletInfo = currentWalletInfo; - newWalletInfo.id = WalletBase.idFor(newName, getType()); - newWalletInfo.name = newName; - - await newWalletInfo.save(); + final newDirPath = await pathForWalletDir(name: newName, type: getType()); + currentWalletInfo.id = WalletBase.idFor(newName, getType()); + currentWalletInfo.name = newName; + currentWalletInfo.dirPath = newDirPath; + currentWalletInfo.path = '$newDirPath/$newName'; + await currentWalletInfo.save(); } @override @@ -135,7 +163,8 @@ class ZanoWalletService extends WalletService< @override Future restoreFromSeed(ZanoRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { - return ZanoWalletBase.restore(credentials: credentials); + return ZanoWalletBase.restore( + credentials: credentials, encryptionFileUtils: encryptionFileUtilsFor(isDirect)); } @override diff --git a/cw_zano/pubspec.yaml b/cw_zano/pubspec.yaml index 7e8ede8dd..63711349c 100644 --- a/cw_zano/pubspec.yaml +++ b/cw_zano/pubspec.yaml @@ -11,6 +11,8 @@ environment: dependencies: flutter: sdk: flutter + bip39: ^1.0.6 + bip32: ^2.0.0 ffi: ^2.0.1 http: ^1.1.0 path_provider: ^2.0.11 @@ -25,7 +27,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c.git - ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d + ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 path: impls/monero.dart dev_dependencies: flutter_test: diff --git a/cw_zano/test/bip39_seed_test.dart b/cw_zano/test/bip39_seed_test.dart new file mode 100644 index 000000000..26cda4c87 --- /dev/null +++ b/cw_zano/test/bip39_seed_test.dart @@ -0,0 +1,38 @@ +import 'package:cw_zano/bip39_seed.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group("Zano bip39 secret derivation", () { + group("Test Wallet 1", () { + final bip39Seed = + 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'; + final expectedSecretDerivation = + "bfafd1eb0e43da200c5c11537d355e458e7c326b3bc1b19f4546573d6bac9d0f"; + final expectedSecretDerivationWithPassphrase = + "674ba1caeaf8a79e66a026858c78d4e565032953e98d39bdea12559bcae86a0c"; + + test("Get secret derivation from bip39", () { + final secretDerivation = getSecretDerivationFromBip39(bip39Seed); + expect(secretDerivation, expectedSecretDerivation); + }); + + test("Get secret derivation from bip39 with passphrase", () { + final secretDerivation = + getSecretDerivationFromBip39(bip39Seed, passphrase: 'TREZOR'); + expect(secretDerivation, expectedSecretDerivationWithPassphrase); + }); + }); + + group("Test Wallet 2", () { + final bip39Seed = + 'melt veteran patrol echo miss fat wrap apple crowd eyebrow weird boring'; + final expectedSecretDerivation = + "8b2693e1d60b0431e3208762bc8a3f232890f50a3fea1e9605ec10a86afe1800"; + + test("Get secret derivation from bip39", () { + final secretDerivation = getSecretDerivationFromBip39(bip39Seed); + expect(secretDerivation, expectedSecretDerivation); + }); + }); + }); +} diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart index d627c1a31..3700a1c84 100644 --- a/lib/core/wallet_creation_service.dart +++ b/lib/core/wallet_creation_service.dart @@ -86,6 +86,7 @@ class WalletCreationService { case WalletType.dogecoin: case WalletType.nano: case WalletType.zcash: + case WalletType.zano: case WalletType.decred: return true; case WalletType.monero: @@ -93,7 +94,6 @@ class WalletCreationService { case WalletType.none: case WalletType.haven: case WalletType.banano: - case WalletType.zano: return false; } } diff --git a/lib/di.dart b/lib/di.dart index 147f1900c..ee904e21f 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -1341,7 +1341,7 @@ Future setup({ case WalletType.wownero: return wownero!.createWowneroWalletService(_unspentCoinsInfoSource); case WalletType.zano: - return zano!.createZanoWalletService(); + return zano!.createZanoWalletService(SettingsStoreBase.walletPasswordDirectInput); case WalletType.decred: return decred!.createDecredWalletService( _unspentCoinsInfoSource, SettingsStoreBase.walletPasswordDirectInput); diff --git a/lib/reactions/wallet_utils.dart b/lib/reactions/wallet_utils.dart index 56bf2080c..57d11a4c8 100644 --- a/lib/reactions/wallet_utils.dart +++ b/lib/reactions/wallet_utils.dart @@ -17,11 +17,11 @@ bool isBIP39Wallet(WalletType walletType) { case WalletType.monero: case WalletType.dogecoin: case WalletType.zcash: + case WalletType.zano: case WalletType.decred: return true; case WalletType.wownero: case WalletType.haven: - case WalletType.zano: case WalletType.none: return false; } diff --git a/lib/src/screens/restore/wallet_restore_from_seed_form.dart b/lib/src/screens/restore/wallet_restore_from_seed_form.dart index d1b5cf0f8..933a5feaf 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -286,7 +286,12 @@ class WalletRestoreFromSeedFormState extends State { 'wallet_restore_from_seed_blockheight_textfield_key', ), onHeightOrDateEntered: widget.onHeightOrDateEntered, - hasDatePicker: [WalletType.monero, WalletType.wownero, WalletType.zcash].contains( + hasDatePicker: [ + WalletType.monero, + WalletType.wownero, + WalletType.zcash, + WalletType.zano, + ].contains( widget.type, ), walletType: widget.type, diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 1a0db8d1c..af8e9b91e 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -13,6 +13,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; +import 'package:cake_wallet/zano/zano.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -606,7 +607,13 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody> final seedWords = seedPhrase.split(' '); if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true; - if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true; + if (walletRestoreViewModel.type == WalletType.zano) { + if (seedWords.length == 26) return true; + if ([12, 24].contains(seedWords.length) && zano!.isBip39Seed(seedPhrase.trim())) { + return true; + } + return false; + } if (seedWords.length == 12 && walletRestoreViewModel.type == WalletType.monero) { return walletRestoreFromSeedFormKey.currentState?.blockchainHeightKey.currentState diff --git a/lib/src/widgets/blockchain_height_widget.dart b/lib/src/widgets/blockchain_height_widget.dart index 273db827f..68160c268 100644 --- a/lib/src/widgets/blockchain_height_widget.dart +++ b/lib/src/widgets/blockchain_height_widget.dart @@ -2,6 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/src/widgets/standard_switch.dart'; import 'package:cake_wallet/utils/date_picker.dart'; import 'package:cake_wallet/wownero/wownero.dart'; +import 'package:cake_wallet/zano/zano.dart'; import 'package:cake_wallet/zcash/zcash.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -200,6 +201,8 @@ class BlockchainHeightState extends State { height = wownero!.getHeightByDate(date: date); } else if (widget.walletType == WalletType.zcash) { height = await zcash!.getHeightByDate(date); + } else if (widget.walletType == WalletType.zano) { + height = zano!.getHeightByDate(date: date); } else { throw Exception("unknown currency in BlockchainHeightWidget"); } diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart index 39e9346b6..f8f1ce1d7 100644 --- a/lib/view_model/advanced_privacy_settings_view_model.dart +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -59,6 +59,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { case WalletType.solana: case WalletType.tron: case WalletType.zcash: + case WalletType.zano: case WalletType.decred: return true; @@ -74,7 +75,6 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store { case WalletType.wownero: case WalletType.none: case WalletType.haven: - case WalletType.zano: return false; } } diff --git a/lib/view_model/wallet_groups_display_view_model.dart b/lib/view_model/wallet_groups_display_view_model.dart index fd8fdc23e..b394da550 100644 --- a/lib/view_model/wallet_groups_display_view_model.dart +++ b/lib/view_model/wallet_groups_display_view_model.dart @@ -128,8 +128,9 @@ abstract class WalletGroupsDisplayViewModelBase with Store { bool isNonSeedWallet = wallet.isNonSeedWallet; - bool isNotMoneroBip39Wallet = - wallet.type == WalletType.monero && di.derivationType != DerivationType.bip39; + bool isNotBip39CoinWallet = + (wallet.type == WalletType.monero || wallet.type == WalletType.zano) && + di.derivationType != DerivationType.bip39; bool isNotDecredBip39Wallet = wallet.type == WalletType.decred && di.derivationType != DerivationType.bip39 && @@ -142,7 +143,7 @@ abstract class WalletGroupsDisplayViewModelBase with Store { isElectrumDerivationType || isSameTypeAsSelectedWallet || isNonSeedWallet || - isNotMoneroBip39Wallet || + isNotBip39CoinWallet || isNotDecredBip39Wallet; } diff --git a/lib/view_model/wallet_new_vm.dart b/lib/view_model/wallet_new_vm.dart index e313ca035..6597776fd 100644 --- a/lib/view_model/wallet_new_vm.dart +++ b/lib/view_model/wallet_new_vm.dart @@ -139,6 +139,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store { name: name, password: walletPassword, passphrase: passphrase, + mnemonic: newWalletArguments!.mnemonic, ); case WalletType.zcash: return zcash!.createZcashNewWalletCredentials( diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 16767a66e..350b21337 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -83,8 +83,13 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { late final bool hasSeedLanguageSelector = [WalletType.monero, WalletType.haven, WalletType.wownero].contains(type); - late final bool hasBlockchainHeightSelector = - [WalletType.monero, WalletType.haven, WalletType.wownero, WalletType.zcash].contains(type); + late final bool hasBlockchainHeightSelector = [ + WalletType.monero, + WalletType.haven, + WalletType.wownero, + WalletType.zcash, + WalletType.zano, + ].contains(type); late final bool hasRestoreFromPrivateKey = [ WalletType.ethereum, @@ -204,13 +209,15 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { height: height, ); case WalletType.zano: - return zano!.createZanoRestoreWalletFromSeedCredentials( + final credentials = zano!.createZanoRestoreWalletFromSeedCredentials( name: name, password: password, height: height, passphrase: passphrase ?? '', mnemonic: seed, ); + credentials.derivationInfo = derivationInfo; + return credentials; case WalletType.decred: return decred!.createDecredRestoreWalletFromSeedCredentials( name: name, @@ -363,6 +370,17 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { seedKey: seedKey, node: node, ); + case WalletType.zano: + final mnemonic = (credentials['seed'] as String?)?.trim() ?? ''; + if (mnemonic.isEmpty) break; + if (zano!.isBip39Seed(mnemonic)) { + return [ + DerivationInfo(derivationType: DerivationType.bip39), + ]; + } + return [ + DerivationInfo(derivationType: DerivationType.unknown), + ]; default: break; } diff --git a/lib/zano/cw_zano.dart b/lib/zano/cw_zano.dart index ce2f82ccc..ab14e332e 100644 --- a/lib/zano/cw_zano.dart +++ b/lib/zano/cw_zano.dart @@ -46,7 +46,7 @@ class CWZano extends Zano { @override List getWordList(String language) { assert(language.toLowerCase() == LanguageList.english.toLowerCase()); - return EnglishMnemonics.words; + return [...zano_bip39.bip39EnglishWords, ...EnglishMnemonics.words]; } @override @@ -61,9 +61,18 @@ class CWZano extends Zano { } @override - WalletCredentials createZanoNewWalletCredentials( - {required String name, required String? password, required String? passphrase}) { - return ZanoNewWalletCredentials(name: name, password: password, passphrase: passphrase); + WalletCredentials createZanoNewWalletCredentials({ + required String name, + required String? password, + required String? passphrase, + String? mnemonic, + }) { + return ZanoNewWalletCredentials( + name: name, + password: password, + passphrase: passphrase, + mnemonic: mnemonic, + ); } @override @@ -122,8 +131,8 @@ class CWZano extends Zano { // } @override - WalletService createZanoWalletService() { - return ZanoWalletService(); + WalletService createZanoWalletService(bool isDirect) { + return ZanoWalletService(isDirect); } @override @@ -146,6 +155,12 @@ class CWZano extends Zano { @override bool validateAddress(String address) => ZanoUtils.validateAddress(address); + @override + bool isBip39Seed(String mnemonic) => zano_bip39.isBip39Seed(mnemonic); + + @override + int getHeightByDate({required DateTime date}) => ZanoUtils.heightByDate(date); + @override Map> debugCallLength() { return api.debugCallLength(); diff --git a/pubspec.lock b/pubspec.lock index cbcdbf567..90493aca9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2050,8 +2050,8 @@ packages: dependency: "direct overridden" description: path: "impls/monero.dart" - ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d" - resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d" + ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 + resolved-ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 url: "https://github.com/mrcyjanek/monero_c.git" source: git version: "0.0.0" diff --git a/pubspec_overrides.yaml b/pubspec_overrides.yaml index b91e7dc84..90cceec37 100644 --- a/pubspec_overrides.yaml +++ b/pubspec_overrides.yaml @@ -960,7 +960,7 @@ dependency_overrides: monero: git: url: https://github.com/mrcyjanek/monero_c.git - ref: 3bfb3856a838f2bf6b729501837bb0295dedf25d + ref: cd4fe366cc8d3c188c91de279f43b29c0e044b15 path: ./impls/monero.dart msgpack_dart: git: diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index 8d0d6e5ae..f4434ab4c 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -16,7 +16,7 @@ fi # NOTE: Make sure to update monero_c prebuilds link in workflow files # https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.6-RC2/release-bundle.zip git fetch -a -git checkout 5952bef2ec01b0b7e57c11613cbdc081dcd727c5 +git checkout cd4fe366cc8d3c188c91de279f43b29c0e044b15 git reset --hard git submodule update --init --force --recursive diff --git a/tool/configure.dart b/tool/configure.dart index a741c2024..2f170465c 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -1178,6 +1178,7 @@ import 'package:cw_core/zano_asset.dart'; import 'package:hive/hive.dart'; """; const zanoCWHeaders = """ +import 'package:cw_zano/bip39_seed.dart' as zano_bip39; import 'package:cw_zano/mnemonics/english.dart'; import 'package:cw_zano/model/zano_transaction_credentials.dart'; import 'package:cw_zano/model/zano_transaction_info.dart'; @@ -1196,12 +1197,12 @@ abstract class Zano { List getWordList(String language); WalletCredentials createZanoRestoreWalletFromSeedCredentials({required String name, required String password, required String passphrase, required int height, required String mnemonic}); - WalletCredentials createZanoNewWalletCredentials({required String name, required String? password, required String? passphrase}); + WalletCredentials createZanoNewWalletCredentials({required String name, required String? password, required String? passphrase, String? mnemonic}); Map getKeys(Object wallet); Object createZanoTransactionCredentials({required List outputs, required TransactionPriority priority, required CryptoCurrency currency}); double formatterIntAmountToDouble({required int amount, required CryptoCurrency currency, required bool forFee}); int formatterParseAmount({required String amount, required CryptoCurrency currency}); - WalletService createZanoWalletService(); + WalletService createZanoWalletService(bool isDirect); CryptoCurrency? assetOfTransaction(WalletBase wallet, TransactionInfo tx); List getZanoAssets(WalletBase wallet); String getZanoAssetAddress(CryptoCurrency asset); @@ -1211,6 +1212,8 @@ abstract class Zano { Future getZanoAsset(WalletBase wallet, String contractAddress); String getAddress(WalletBase wallet); bool validateAddress(String address); + bool isBip39Seed(String mnemonic); + int getHeightByDate({required DateTime date}); Map> debugCallLength(); bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress); } From 6df6108d37d3e4b2cbbd2968d3728dc8310fdf60 Mon Sep 17 00:00:00 2001 From: Omar Date: Sat, 29 Aug 2026 15:37:13 +0800 Subject: [PATCH 3/4] update app version --- scripts/android/app_env.sh | 6 +++--- scripts/ios/app_env.sh | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index e62272ee9..e69e908aa 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -15,14 +15,14 @@ APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" MONERO_COM_VERSION="6.4.2" -MONERO_COM_BUILD_NUMBER=4166 +MONERO_COM_BUILD_NUMBER=4167 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.2" -CAKEWALLET_BUILD_NUMBER=4421 +CAKEWALLET_VERSION="6.4.3" +CAKEWALLET_BUILD_NUMBER=4423 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 9bf2dc05b..33dedff14 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,12 +13,12 @@ APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" MONERO_COM_VERSION="6.4.2" -MONERO_COM_BUILD_NUMBER=172 +MONERO_COM_BUILD_NUMBER=173 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="6.4.2" -CAKEWALLET_BUILD_NUMBER=435 +CAKEWALLET_VERSION="6.4.3" +CAKEWALLET_BUILD_NUMBER=437 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" From df87bab8367c5e712f668db3b2f9a32a87957a62 Mon Sep 17 00:00:00 2001 From: Konstantin Ullrich Date: Tue, 1 Sep 2026 08:52:57 +0200 Subject: [PATCH 4/4] feat: add fallback locktime support in PSBT deserialization (#3583) --- cw_bitcoin/lib/psbt/v0_deserialize.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/cw_bitcoin/lib/psbt/v0_deserialize.dart b/cw_bitcoin/lib/psbt/v0_deserialize.dart index 541eb6928..d458a1fce 100644 --- a/cw_bitcoin/lib/psbt/v0_deserialize.dart +++ b/cw_bitcoin/lib/psbt/v0_deserialize.dart @@ -20,6 +20,7 @@ extension PsbtSigner on PsbtV2 { setGlobalInputCount(tx.inputs.length); setGlobalOutputCount(tx.outputs.length); setGlobalTxVersion(Uint8List.fromList(tx.version).readUint32LE(0)); + setGlobalFallbackLocktime(Uint8List.fromList(tx.locktime).readUint32LE(0)); for (var i = 0; i < getGlobalInputCount(); i++) { inputMaps.insert(i, {});